plpgsql how to just execute query in a function or procedure - sql

I am beginning to learn stored procedures and functions in sql in a postgres database.
I need an example to get me going for what I am trying to accomplish.
I need to run a procedure and have it return results. For example something like this:
run_query(name):
begin
return select * from employees where first_name = $name
end
end
I want something like the above to return the result set when I run it. Is this possible? thank you for your help in advance!
Here is the function im trying to create:
CREATE OR REPLACE FUNCTION test() RETURNS TABLE(id INT, subdomain varchar, launched_on_xxx timestamp, UVs bigint, PVs bigint) AS
'SELECT dblink_connect(''other_DB'');
SELECT c.id as id, c.subdomain, c.launched_on_xxx, COALESCE(SUM(tbd.new_unique_visitors), 0) AS UVs, COALESCE(SUM(tbd.page_views), 0) AS PVs
FROM dblink(''SELECT id, subdomain, launched_on_xxx FROM communities'')
AS c(id int, subdomain character varying, launched_on_xxx timestamp)
LEFT OUTER JOIN days_of_center tbd
ON c.id = tbd.community_id
WHERE c.launched_on_xxx < now()
GROUP BY c.id, c.subdomain, c.launched_on_xxx;
SELECT dblink_disconnect();'
LANGUAGE SQL;

Your function could look like this:
CREATE OR REPLACE FUNCTION test()
RETURNS TABLE(id int, subdomain varchar, launched_on_xxx timestamp
,uvs bigint, pvs bigint) AS
$func$
SELECT dblink_connect('other_DB');
SELECT c.id
,c.subdomain
,c.launched_on_xxx
,COALESCE(SUM(tbd.new_unique_visitors), 0) AS uvs
,COALESCE(SUM(tbd.page_views), 0) AS pvs
FROM dblink('
SELECT id, subdomain, launched_on_xxx
FROM communities
WHERE launched_on_xxx < now()')
AS c(id int, subdomain varchar, launched_on_xxx timestamp)
LEFT JOIN days_of_center tbd ON tbd.community_id = c.id
GROUP BY c.id, c.subdomain, c.launched_on_xxx;
SELECT dblink_disconnect();
$func$ LANGUAGE SQL;
Pull the WHERE clause down into the dblink function. It's much more effective not to fetch rows to begin with - instead of fetching them from the external database and then discarding them.
Use dollar-quoting to avoid confusion with quoting. That has become standard procedure with bigger function definitions.
To output it in "table format", call a function returning multiple columns like this:
SELECT * FROM test();

Just about the simplest possible example would be this;
CREATE FUNCTION test() RETURNS TABLE(num INT) AS
'SELECT id FROM table1'
LANGUAGE SQL;
SELECT * FROM test()
An SQLfiddle to test with.
If you need a parameter, here's another example;
CREATE FUNCTION test(sel INT) RETURNS TABLE(val VARCHAR) AS
'SELECT value FROM table1 WHERE id=sel'
LANGUAGE SQL;
SELECT * FROM test(2)
Another SQLfiddle to test with.

Related

Create a function that accepts list of ids?

I would like to do create a SQL function like this (pseudocode):
function PeopleInCompanies(companyIds)
SELECT * from Person WHERE CompanyId IN (companyIds)
end function
and call it like this:
define companyIds = 1,2,3
select * from PeopleInCompanies(companyIds)
is it even possible?
You would need to use a table type parameter. Assuming that CompanyID is an int:
CREATE TYPE dbo.ints AS TABLE ([value] int);
GO
CREATE FUNCTION dbo.PeopleInCompanies (#CompanyID dbo.ints READONLY)
RETURNS TABLE
AS RETURN
SELECT P.* --This should be replaced by the columns you need.
FROM dbo.Person P
JOIN #CompanyID CI ON P.CompanyID = CI.[Value];
Then you would call the function using:
DECLARE #CompanyID dbo.ints;
INSERT INTO #CompanyID
VALUES (1),(2),(3);
SELECT *
FROM dbo.PeopleInCompanies(#CompanyID);
SQL Server does not support macro substitution. That said, you have the table type as Gordon and Larnu mentioned, or you can simply parse/split the delimited string
Just another option
Declare #companyIds varchar(max) = '1,2,3'
Select A.*
From Person A
Join string_split(#companyIds,',') B
on A.CompanyID = B.Value

Unable to pass arguments in crosstab function postgres

I know that I have to pass text to crosstab function in postgres. But somehow I am unable to do it. I am not sure what am I doing wrong please Help. This is the function I am trying to create
create or replace function hrms.test2(startdate date)
returns table(
employeeid int,
col1 int,
col2 INT,
col3 int,
col4 int) as
$body$
SELECT * FROM hrms.crosstab(
$firstquery$
SELECT tms.employeeid,tms.today,count(tms.employeeid) as countid
FROM hrms.timesheet as tms
where dated>=|| quote_literal(startdate) ||
and dated < ||+ quote_literal(startdate)||::timestamp + '1 MONTH'::INTERVAL
group by tms.employeeid,tms.today $firstquery$,
$secquery$ select distinct tms.today
from hrms.timesheet as tms$secquery$
)as
finalresult(employeeid int,leave int,present int,absent int, holiday int)
$body$
LANGUAGE SQL;
It runs successfully but When I run it using a date like
select * from hrms.test2('2017-09-01')
I get an error message saying
column startdate doesn't exist
I have tried a few more alternatives as well. I am not sure what am I doing wrong Please help.
You forgot to wrap out variables with quoting $firstquery$, fro your code I assume you wanted smth like:
create or replace function hrms.test2(startdate date)
returns table(
employeeid int,
col1 int,
col2 INT,
col3 int,
col4 int) as
$body$
SELECT * FROM hrms.crosstab(
$firstquery$
SELECT tms.employeeid,tms.today,count(tms.employeeid) as countid
FROM hrms.timesheet as tms
where dated>=$firstquery$|| quote_literal(startdate) ||$firstquery$
and dated < $firstquery$||+ quote_literal(startdate)||$firstquery$::timestamp + '1 MONTH'::INTERVAL
group by tms.employeeid,tms.today $firstquery$,
$secquery$ select distinct tms.today
from hrms.timesheet as tms$secquery$
)as
finalresult(employeeid int,leave int,present int,absent int, holiday int)
$body$
LANGUAGE SQL;
you can basically use $$ instead of $firstquery$ or $secondquery$.
i dont have rep to comment so i left a reply.

How do I create a function to accept [[customerID]] and return CustName Please look at details

I have been asked to created a Function to accept CustomerID and return CustomerName for the CustomerID, I m a new Student/Developer Please if the question is not clear let me know so i can add more details about it, but that is what I was exactly asked.
functions in SQL are of three types.ignoring rest CLR functions ...
create table test
(
id int,
name varchar(4)
)
insert into test
select 1,'abc'
union all
select 2,'cde'
1.Scalar function takes one value and return one value
now for the above table ,you can create scalar function like below
create function dbo.test
(
#id int
)
returns varchar(4)
as
begin
declare #name varchar(4)
select #name=name from test where id =#id
return #name
End
You invoke it like:
select dbo.test(1)
2.Inline table valued functions:takes a single input same like scalar functions and returns table
create function dbo.test
(
#id int
)
as
returns TABLE
(
select * from test where id=#id)
You invoke it like:
select * from dbo.test(1)
3.Multi table valued function:
create function dbo.test
(
#id int
)
returns
#test table
(
id int,
name varchar(4)
)
as
begin
insert into #test
select * from test where id =#id
return
end
You invoke it like:
select * from dbo.test(1)
Take any one of Itzik Ben Gan books and start learning SQL the way it should be learned

SQL Function within Function

I have a function that gets the recipeid. I am creating another function that shows the average price with recipename. How do I use the first function within the second function?
This is what I have so far. As can be seen, I am using a join for RecipeID, but I want it to use the 1st function I have (let's call it function1) that gets the ID instead. How do I go about this?
CREATE FUNCTION AveragePriceforRecipe() RETURNS #PriceTable TABLE (
[Amount] smallmoney,
[RecipeName] nvarchar(75)) AS
BEGIN
INSERT INTO #PriceTable
SELECT AVG(Amount)
FROM Prices JOIN
RecipePrices ON Prices.PriceID = RecipePrices.PriceID JOIN
Recipes ON RecipePrices.RecipeID = Recipes.RecipeID
END
are you using ms sql server (t-sql)? if so, please try the code below:
given that function1 is:
CREATE FUNCTION function1(#RecipeName)
RETURNS INT
AS
BEGIN
DECLARE #RecipeID INT
SELECT #RecipeID = ID
FROM Recipes
WHERE RecipeName = #RecipeName
RETURN #RecipeID
END
getting the recipes price table using function1:
CREATE FUNCTION AveragePriceforRecipe (#Amount SMALLMONEY, #RecipeName NVARCHAR(75))
RETURNS #PriceTable TABLE
AS
BEGIN
INSERT INTO #PriceTable
SELECT AVG(Amount)
FROM Prices
JOIN RecipePrices ON Prices.PriceID = RecipePrices.PriceID
AND RecipePrices.RecipeID = function1(#RecipeName)
END

SQL UDF Group By Parameter Issue

I'm having some issues with a group by clause in SQL. I have the following basic function:
CREATE FUNCTION dbo.fn_GetWinsYear (#Year int)
RETURNS int
AS
BEGIN
declare #W int
select #W = count(1)
from tblGames
where WinLossForfeit = 'W' and datepart(yyyy,Date) = #Year
return #W
END
I'm trying to run the following basic query:
select dbo.fn_GetWinsYear(datepart(yyyy,date))
from tblGames
group by datepart(yyyy,date)
However, I'm encountering the following error message: Column 'tblGames.Date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Any ideas why this is occurring? FYI, I know I can remove the function and combine into one call but I'd like to keep the function in place if possible.
I think you should be calling your function like this.
select dbo.fn_GetWinsYear(datepart(yyyy,getdate()))
OR
select dbo.fn_GetWinsYear('2010')
Essentially you are just passing a year to your function and the function is returning the number of wins for that year.
If you don't know the year, your function could look something like this...
CREATE FUNCTION dbo.fn_GetWinsYear ()
RETURNS #tblResults TABLE
( W INT, Y INT )
AS
BEGIN
INSERT #tblResults
SELECT count(1), datepart(yyyy,[Date])
FROM tblGames
WHERE WinLossForfeit = 'W'
GROUP BY datepart(yyyy,[Date])
RETURN
END
SELECT * FROM dbo.fn_GetWinsYear()