I have a basic table that looks like the following:
SQL> desc comments
Name Null? Type
---------------------------------------
COMMENT_ID NOT NULL NUMBER
POST_ID NOT NULL NUMBER
USER_ID NOT NULL NUMBER
MESSAGE NOT NULL VARCHAR2(2500)
MESSAGE_TIME NOT NULL TIMESTAMP(6)
UPVOTES NOT NULL NUMBER
What I'd like to do is have a stored procedure be called that would increment the upvotes. This seems to make the most sense because I don't want to pass in anything other than the comment_id and post_id.
I think I should be doing something like this (please excuse syntax, I haven't messed with stored procedures in a long long time)
CREATE OR REPLACE procedure proc_upvote_comment (comment_id NUMBER , post_id NUMBER)
BEGIN
SELECT UPVOTES FROM COMMENTS
WHERE COMMENTS.COMMENT_ID = proc_upvote_comment.comment_id
AND COMMENTS.POST_ID = proc_upvote_comment.post_id;
//Call an update
END;
/
But I just don't seem to know the missing piece here. I've tried looking at
http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_packages.htm#i1007682
http://docs.oracle.com/cd/B12037_01/server.101/b10759/statements_6009.htm
And a few other places on the site - but I'm just missing something.
Any help in the right direction would be great
Is there any reason this is not working for you:
CREATE OR REPLACE procedure proc_upvote_comment (comment_id NUMBER , post_id NUMBER)
AS
BEGIN
UPDATE COMMENTS
SET UPVOTES = UPVOTES + 1
WHERE COMMENTS.COMMENT_ID = proc_upvote_comment.comment_id
AND COMMENTS.POST_ID = proc_upvote_comment.post_id;
END;
Remember that SQL works with sets ;)
You probably just want
CREATE OR REPLACE procedure proc_upvote_comment (p_comment_id NUMBER , p_post_id NUMBER)
AS
BEGIN
UPDATE comments
SET upvotes = upvotes + 1
WHERE comment_id = p_comment_id
AND post_id = p_post_id;
END;
/
Generally, you want to have a naming convention to differentiate parameters from column names. I prefer using the p_ prefix for parameters and the l_ prefix for local variables but there are other conventions. If you don't do this and you use the same name for a column and for a parameter, the SQL statement will resolve identifiers first using the name of the column and then using the name of the parameter. Resorting to prefixing the name of the stored procedure to provide scope resolution works but it's rather cumbersome.
Related
I am trying to build bigquery stored procedure where I need to pass the table name as a parameter. My code is:
CREATE OR REPLACE PROCEDURE `MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES` (table_name STRING)
BEGIN
----step 1
CREATE OR REPLACE TABLE `MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES_01` AS
SELECT DISTINCT XX.HH_ID, A.ECR_PRTY_ID, XX.ANCHOR_DT
FROM table_name XX
LEFT JOIN
(
SELECT DISTINCT HH_ID, ECR_PRTY_ID
FROM `analytics-mkt-cleanroom.Master.EDW_ECR_ECR_MAPPING`
WHERE HH_ID NOT LIKE 'U%'
AND ECR_PRTY_ID IS NOT NULL
)A
ON XX.HH_ID = A.HH_ID----one (HH) to many (ecr)
;
END;
CALL MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES(`analytics-mkt-cleanroom.MKT_DS.Home_Services_Multi_Class_Aesthetic_Baseline_Final_Training_Sample`);
I followed a couple of similar questions here and here, tried writing an EXECUTE IMMEDIATE version of the above but not able to work out the right syntax.
I think issue is; the SELECT statement in my code is selecting multiple columns XX.HH_ID, A.ECR_PRTY_ID, XX.ANCHOR_DT and the EXECUTIVE IMMEDIATE setup is meant to work only for one column. But I'm not sure. Please advise. Thank you.
I am basically trying to write stored procedures for data pipeline building.
Hope below is helpful.
pass a parameter as a string.
CALL MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES(`analytics-mkt-cleanroom.MKT_DS.Home_Services_Multi_Class_Aesthetic_Baseline_Final_Training_Sample`);
-->
CALL MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES('analytics-mkt-cleanroom.MKT_DS.Home_Services_Multi_Class_Aesthetic_Baseline_Final_Training_Sample');
use EXECUTE IMMEDIATE since a table name can't be parameterized as a variable in a query.
----step 1
EXECUTE IMMEDIATE FORMAT("""
CREATE OR REPLACE TABLE `MKT_DS.PXV2DWY_CREATE_PROPERTY_FEATURES_01` AS
SELECT DISTINCT XX.HH_ID, A.ECR_PRTY_ID, XX.ANCHOR_DT
FROM `%s` XX
LEFT JOIN
(
SELECT DISTINCT HH_ID, ECR_PRTY_ID
FROM `analytics-mkt-cleanroom.Master.EDW_ECR_ECR_MAPPING`
WHERE HH_ID NOT LIKE 'U%%'
AND ECR_PRTY_ID IS NOT NULL
)A
ON XX.HH_ID = A.HH_ID----one (HH) to many (ecr)
;
""", table_name);
escape % in a format string with additional %
LIKE 'U%'
-->
LIKE 'U%%'
see PARSE_DATE not working in FORMAT() in BigQuery
I am trying to update the values of a table dynamically, using stored procedure. My stored procedure is as follows,
CREATE OR REPLACE PROCEDURE Update
(
IN ID1 BIGINT,
IN SOURCE1 VARCHAR(100),
IN NAME1 VARCHAR(100)
)
DYNAMIC RESULT SETS 2
LANGUAGE SQL
BEGIN
UPDATE MessageTable
SET SOURCE=SOURCE1,
NAME=NAME1
WHERE ID=ID1;
END
When I try to pass the value for ID1 and SOURCE1 alone, the values are not getting updated. When I pass all the three values, they are getting updated properly. My requirement is even if I pass two values it should get updated. I tried giving DEFAULT NULL for the arguments. Since the fields are declared NOT NULL, it was not working. Could someone help to overcome this. The stored procedure should work even if I pass single value. Thanks in advance.
You could use COALESCE:
UPDATE MessageTable
SET SOURCE = COALESCE(SOURCE1, SOURCE),
NAME = COALESCE(NAME1, NAME)
WHERE ID = ID1;
When NAME1 is NULL then the original NAME will be preserved.
You could check with IF or another statement whether all arguments have non-NULL values and then switch to either an UPDATE statement that sets one or two column values.
I am using Postgresql9.2 and SQLAlchemy0.8 . I have a stored procedure in database which has many out parameters and i want them to use by dot notation. But so far I have failed miserably. Below is how my code looks like.
An example to show what i am doing is as follows.
CREATE OR REPLACE FUNCTION stored_proc_name(IN in_user_id bigint, IN in_amount bigint,
OUT pout_one bigint, OUT pout_two bigint )
RETURNS record AS
$BODY$
begin
select count(*) as AliasOne into pout_one from tabe_names where conditions;
select user_name as AliasTwo into pout_two from table_name where condition;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION stored_proc_name(bigint, bigint)
OWNER TO postgres;
My code snippet is as following:
#session object from sessionmaker
result_obj = session.execute(func.stored_proc_name(user_id, amount))
print result_obj.fetechall()
#The above print statement prints following on the console.
>> [('(1,100)',)]
Clearly the above result fetches string. What I want is something like result_obj.pout_one and use it in my code.
Is there any way of achieving it. A working code snippet will be highly appreciated.
Thanks a lot!
You could try something like this:
query = select([column('pout_one'), column('pout_two')],
from_obj=[func.stored_proc_name(user_id, amount)])
session.execute(query)
The inspiration for this is from the SQLAlchemy list where someone asked a similar question. This could result in the desired output (I can't test it right now).
I am trying to teach myself SQL. I have a web matrix project I am working on to edit and display posts backed by a SQL server Datatabase. A work colleague suggested I use a Stored Procedure to commit the post rather than writing the sql inline.
So far the procedure looks ok but I would like to check if the url slug already exists, and if so return something to say so (The url slug should be unique). I'm struggling with how I am supposed to check before the insert. I have also read that it is bad practice to return from a stored procedure, but I thought it would be a good idea to return something to let the caller know the insert did not go ahead.
Any help would be very much appreciated.
-- =============================================
-- Author: Dean McDonnell
-- Create date: 05/12/2011
-- Description: Commits an article to the database.
-- =============================================
CREATE PROCEDURE CommitPost
#UrlSlug VARCHAR(100),
#Heading VARCHAR(100),
#SubHeading VARCHAR(300),
#Body VARCHAR(MAX)
AS
INSERT INTO Posts(UrlSlug, Heading, SubHeading, Body, Timestamp)
VALUES(#UrlSlug, #Heading, #SubHeading, #Body, GETDATE())
This is what I have so far.
CREATE PROCEDURE CommitPost
#UrlSlug VARCHAR(100),
#Heading VARCHAR(100),
#SubHeading VARCHAR(300),
#Body VARCHAR(MAX)
AS
IF NOT EXISTS (SELECT * FROM Posts WHERE UrlSlug = #UrlSlug)
INSERT INTO Posts(UrlSlug, Heading, SubHeading, Body, Timestamp)
VALUES(#UrlSlug, #Heading, #SubHeading, #Body, GETDATE())
SELECT ##ROWCOUNT
To check for existance, do a SELECT COUNT like so:
CREATE PROCEDURE CommitPost
#UrlSlug VARCHAR(100),
#Heading VARCHAR(100),
#SubHeading VARCHAR(300),
#Body VARCHAR(MAX)
AS
DECLARE #count INT
SELECT #count = COUNT(*) FROM Posts WHERE UrlSlug = #UrlSlug
IF #count = 0 THEN
BEGIN
INSERT INTO Posts(UrlSlug, Heading, SubHeading, Body, Timestamp)
VALUES(#UrlSlug, #Heading, #SubHeading, #Body, GETDATE())
END
You may set an unique index on UrlSlug to make the database reject insertions of urls already in the database, but nonetheless you should check before inserting.
If your caller wants to know if the row was inserted, return the #count value. If it's 0 then the line was inserted, else not. I'm not aware of a "bad practice" regarding to return values from a SP. As a SP does not have a result, though, you need to use an out parameter.
If you do just one SQL statement like this insert you could just use paratemerized query i.e. I assume that you are using .NET.
If you want to return values I would suggest that you use a FUNCTION instead of a STORED PROCEDURE. You can return either tables or whatever you want from a function.
There are some limitations though. You can dig a little deeper into the differences to see what is used when. Here's a link that can help you out get started:
Function vs. Stored Procedure in SQL Server
If you want to use stored procedure anyway, you can either return a single row, single column result set, using SELECT, or just use an output parameter.
If you want to do actions depending of whether the column exists or not I would suggest that you look into MERGE statement.That way you would perform only one query to the database instead of two or more(doing SELECT and then INSERT).
There are also other ways to use database access like various ORMs on top of the database in the code that will make your life easier, like LINQ-to-SQL etc. There are a lot of possibilities out there. You need to determine what's best in a given situation.
I need a stored procedure which in parameter have name of table(varchar) and it return names of columns in this specific table.
It is possible ? I think about some SELECT which retrieve this names from table but I am weak at SQL :/
I add that I use Firebird 1.5 :/
You don't need stored procedure. Just a simple request can make this :
SELECT r.RDB$FIELD_NAME AS field_name
FROM RDB$RELATION_FIELDS r WHERE
r.RDB$RELATION_NAME='TABLE_NAME' --table name
ORDER BY r.RDB$FIELD_POSITION;
you can learn more here : http://www.alberton.info/firebird_sql_meta_info.html