Returning a table in firebird 3.0 with stored function or stored procedure - sql

I'm trying to write a stored procedure/function that returns me a table with one or multiple rows of data.
The returned data depends on a variable shown in the following sql statement:
SELECT * FROM table_name AS SD WHERE EXISTS
(SELECT DISTINCT S.PARENT_ID FROM table_name AS S
WHERE S.COMPONENT_ID = 10011 AND S.CARRIER_GROUP_ID = X AND SD.SD_ID = S.PARENT_ID)
So far I have seen that something is done like this:
CREATE FUNCTION f_test_function (X INT)
RETURNS TABLE
AS
RETURN
(SELECT * FROM table_name AS SD WHERE EXISTS
(SELECT DISTINCT S.PARENT_ID FROM table_name AS S
WHERE S.COMPONENT_ID = 10011 AND S.CARRIER_GROUP_ID = X AND SD.SD_ID = S.PARENT_ID));
Afterwards you call the function/procedure with a X value. I know that there is something wrong with the returns type but I don't know what.
Can anyone help?

What you are looking for is a selectable stored procedure. Firebird requires you to explicitly declare the columns the stored procedure returns, so something like returns table is not an option. For example:
create procedure sp_test_procedure (x integer)
returns (column1 integer, column2 varchar(50))
as
begin
for select value1, value2
from table_name SD
where exists (
SELECT DISTINCT S.PARENT_ID
FROM table_name AS S
WHERE S.COMPONENT_ID = 10011
AND S.CARRIER_GROUP_ID = :X
AND SD.SD_ID = S.PARENT_ID)
into column1, column2
do
begin
suspend;
end
end
You will need to explicitly map the columns, so a simple select * is not a good idea.
Note the use of for select, which selects zero or more rows and iterates over the cursor, and suspend, which outputs a row to be fetched from the stored procedure (in this case for each row of the cursor).
You can produce values from this procedure like:
select column1, column2
from sp_test_procedure(10)

Related

How can I join different result of a query from a table to another table in a stored procedure

I have tree tables:
Products (Fields: Reference, ...)
InvoiceHeader (Fields: In_No,In-Date,Type, ...)
InvoiceDetails (Reference, Qty, ...)
I want to write a stored procedure which return all the references with the Stock of them.
Invoices are two types: input (which add to stock) and output (which subtract from stock).
It means I have to run a query for two times on InvoiceHeader joining InvoiceDetails on for having inputs of all the references and one for having outputs of the references.
Then I have to join these two queries to the products and make a new field (remain) which minus output from input for each reference.
The results should be like this:
Reference Input Output Remain
X 5 2 3
Y 10 3 7
Z 1 1 0
How can I write the procedure?
Could you please precise what do you would like to know? How to pass 3 values to output, select 3 values, or 'do the job' inside the procedure?
SQL server supports having more than one output value. So If that is your issue you can use for example that blog post which describes how to do that. If your goal is to have procedure which selects these values, but they will not be used in the future you can just... select them in the procedure body... as per below
create procedure as X
begin
select ...
select ...
select ...
end
You can write a procedure with table result set output, like this:
CREATE PROCEDURE my_stored_proc
#param1 INT,
#param2 INT
AS
BEGIN
SELECT T.field1,
T.field2
FROM my_table AS T
WHERE T.field3 = #param1
AND T.field4 = #param2
END
so when executing the procedure, you'd get the result same as executing SELECT statement.
In sql-server (mssql) you can "collect" the output result-set like this:
DECLARE #output1 AS TABLE (field1 INT, field2 INT)
INSERT INTO #output1
EXEC my_stored_proc #param1 = 1, #param2 = 2
you can then use the collected output with any other query, like this:
SELECT T.field2 * 2 + T.field1
FROM #output1 AS T
JOIN some_table6 AS T6 ON T6.id = T.field1

Combine sp result in select as column

I am trying to execute sp as sub query and treat result set of sp as column of outer query . Some thing like this
Select U.FirstName , (exec SomeSP ) as columnFromSP from User U
Is this possible i searched alot but found nothing on google.
Update
I cannot use #temp table because i am trying to do without #temp table
If you are able to convert your USP to a table value UDF, you will be use the UDF in your FROM statement.
CREATE FUNCTION dbo.SomeUDF
(
-- Add the parameters for the function here
#param varchar(1000)
)
RETURNS TABLE
AS
RETURN
(
SELECT #param as Value
)
GO
SELECT
a.Value,
'B' as Value2
FROM dbo.SomeUDF('ABC') a
Not possible, but you can work around it
Create a temp table & insert the results of the procedure into
it
Now join the User table with the temporary table and select the
columns you want from both tables
This assumes however, you have a joinable expression returned from the stored proc (one that you can match to a field in the user table). If the stored procedure on returns a single row, use a condition of 1=1 or something similar
-- Declare a temp table and column(for eg you have only 1 column)
CREATE TABLE #TEMP
(
FirstName VARCHAR(50)
)
-- The results after execution will be inserted to this table
INSERT INTO #TEMP
Exec SomeSP 'Params'
-- Select records from both tables in all combinations
SELECT U.FirstName , COL1 as columnFromSP
from User U
CROSS JOIN #TEMP

SQL query for finding all tables ROWS with two columns in them

I have a DataBase with around +100 tables, like half of tables have column A & column B.
My question is, Can I query all tables that have this columns with a specific values e.g.
SELECT * FROM DATABASE
WHERE
EACHTABLE HAS COLUMN A = 21 //only if table has columns and then values
AND
COLUMN B = 13
I am not sure how exact I will do it, nothing is coming up on google either
You can use the undocumented MS stored procedure sp_MSforeachtable, if you fancy living life recklessly:
create table T1 (
ColumnA int not null,
ColumnB int not null
)
go
create table T2 (
ColumnA int not null,
Column2 int not null
)
go
create table T3 (
Column1 int not null,
ColumnB int not null
)
go
create table T4 (
ColumnA int not null,
ColumnB int not null
)
go
insert into T1 values (1,2);
insert into T2 values (3,4);
insert into T3 values (5,6);
insert into T4 values (7,8);
go
create table #Results (TableName sysname,ColumnA int,ColumnB int)
exec sp_MSforeachtable 'insert into #Results select ''?'',ColumnA,ColumnB from ?',
#whereand = ' and syso.object_id in (select object_id from sys.columns where name=''ColumnA'') and syso.object_id in (select object_id from sys.columns where name=''ColumnB'')'
select * from #Results
drop table #Results
Result:
TableName ColumnA ColumnB
------------------------------------- ----------- -----------
[dbo].[T1] 1 2
[dbo].[T4] 7 8
By default, sp_MSforeachtable will, as its name implies, perform the same task for each table in the database. However, one optional parameter to this procedure, called #Whereand, can be used to modify the WHERE clause of the internal query that enumerates the tables in the database. It helps to know that this internal query has already established two aliases to some of the system views. o is an alias for sysobjects (the legacy system view). syso is an alias for sys.all_objects (a more modern system view).
Once sp_MSforeachtable has decided which tables to run against, it will execute the query given to it as its first parameter. But, it will replace ? with the schema and table name (? is the default replacement character. This can be changed as needed)
In this case, I chose to create a temp table, then have each selected table store its results into this temp table, and after sp_MSforeachtable has finished running, to select the combined results out with no further processing.
There is a similar (and similarly undocumented) procedure called sp_MSforeachdb which will access each user database on the server. These can even be combined (although you have to be careful with doubling up ' quote characters twice, at times). However, there's no equivalent sp_MSforeachcolumn.
Try this:
select t.name from sys.objects t inner join sys.columns c
on t.name=OBJECT_NAME(c.object_id)
where t.type='U'
and c.name in('col1','col2')
group by t.name
having COUNT(*) = 2
order by 1
Then you just loop through all the tables and fine the values for these columns.
Like
Declare #out TABLE(tblname varchar(100))
if exists(select * from tbl1 where col1='21' and col2='22')
BEGIN
INSERT INTO #out
select tbl1
END
You can try like this using dynamic query.
select 'select * from '+table_name+ ' where'+column_name+'=21'
from information_schema.columns where column_name = 'A'
I suggest to use two steps:
First, find out all tables in your database that have these two columns and use it for a temporal derived table. For I am not an expert in SQL-Server 2008 I recommend to have a look at the whitepages.
The expression might look like this:
SELECT tablename
FROM information_schema.tables sdbt
WHERE "column a" IN
(SELECT columns
FROM information_schema.columns col
WHERE col.tablename = sdbt.tablename)
Second, use a expresssion to filter the results according to your demanded values.
This command should do the trick in one go, only for column A, amend accordingly to include any other columns you need:
exec sp_MSforeachtable
#command1=N'SELECT * FROM ? WHERE A = 21',
#whereand=' and o.name IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ''A'') '

IF condition in view in SQL Server

Is it possible to have a if condition in VIEWS
eg
CREATE VIEW
as
DECLARE #Count int
SET #Count=-1
select #Count=EmpID from EmployeeDetails where ID=200
IF #Count=-1
BEGIN
SELECT * FROM TEAM1
END
ELSE
BEGIN
SELECT * FROM TEAM1
END
You could try something sneaky with a UNION :
SELECT {fieldlist}
FROM Table1
WHERE EXISTS(SELECT EmpID FROM EmployeeDetails WHERE ID = 200)
UNION ALL
SELECT {fieldlist}
FROM Table2
WHERE NOT EXISTS(SELECT EmpID FROM EmployeeDetails WHERE ID = 200)
This method would require both SELECT statements to return the same set of fields, although their sources might be different.
Views only allow select statements as stated in here
if you need to do if on column values you can use a
SELECT
CASE WHEN COLUMN1 = 1 THEN COLUMNX ELSE COLUMNY END
FROM TABLE1
if your need exceeds this you should create a select from a table valued function instead of a view.
What you need is a simple Procedure
CREATE PROCEDURE DOSOMETHING
(
#ID INT
)
AS
BEGIN
IF #ID > 100
SELECT 1 AS ID,'ME' AS NAME, GETDATE() AS VARIABLEDATECOL, NEWID() AS VARIABLEGUID
ELSE
SELECT 2 AS ID, 'YOU' AS NAME
END
No I don't believe this is possible.
You could use a stored procedure instead to achieve this functionality.
simply use a udf (User defined Function)
Here you can use IF, ELSE, WHILE etc.
But when you are manipulating data (INSERT, UPDATE, DELETE) then you have to use Stored Procedures because udf's aren't able to do that

SQL Select Statement including SP Call has syntax error

MYTABLE has ID column. However, following query generates syntax error.
SELECT ID FROM MYTABLE
WHERE ID = EXEC MY_SP ID
What do you think is wrong here?
You can't call stored procedures inline like this.
A couple of options include:
1) Execute the stored procedure and store the results in a temp table. Then use that temp table.
e.g.
CREATE TABLE #Example
(
ID INTEGER
)
INSERT #Example
EXECUTE My_SP
SELECT t.ID FROM MyTable t JOIN #Example e ON t.ID = e.ID
DROP TABLE #Example
2) convert the sproc to a user defined function which you CAN call inline
e.g.
CREATE FUNCTION dbo.MyFunc()
RETURNS TABLE
AS
RETURN
(
SELECT ID FROM SomeTable WHERE ....
)
SELECT t.ID FROM MyTable t JOIN dbo.MyFunc() f ON t.ID = f.ID
3) If the sproc returns a single ID, consider returning an OUTPUT parameter from the sproc instead and use like this:
DECLARE #ID INTEGER
EXECUTE MY_SP #ID OUTPUT
SELECT ID FROM MYTABLE
WHERE ID = #ID
I don't think you need the exec statement, just call the sp, exec is expected to be a separate statement
I don't think you can do that at all. Are you perhaps thinking of a User Defined Function rather than a stored Procedure. Based on the context, you'll need a scalar UDF.
Try this:
SELECT ID FROM MYTABLE WHERE ID = ##SPID