I have one complex stored procedure that returns some rows with some calculated values
SELECT CalculatedField1 ,
CalculatedField2 ,
...
FROM ...
WHERE CONDITION
this sproc (lets call it procA) returns variable number of rows, depending on the WHERE condition. This works fine. What I need to do now is to write a stored procedure that will get the summary of these returned rows.
-- procB
SELECT SUM(CalculatedField1),
SELECT SUM(CalculatedField2),
...
FROM (EXEC procA params)
Is this possible?
Edit: creating a temp table did the job, however I have problems with passing output pareters.
CREATE PROCEDURE [dbo].[sprocB] (#prm INT = NULL OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SET #prm = 1
SELECT Id FROM dbo.AnyTable
END
CREATE PROCEDURE [dbo].[sprocA] (#prm INT = NULL OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #temp (Id INT)
INSERT INTO #temp
EXEC sprocB #prm
SELECT Id FROM #temp
END
To execute:
USE [MyDatabase]
GO
DECLARE #return_value int,
#prm int
EXEC #return_value = [dbo].[sprocA]
#prm = #prm OUTPUT
SELECT #prm as N'#prm'
SELECT 'Return Value' = #return_value
GO
The results from temp table are ok, resultset is retrieved correctly, however #pem value is still NULL.
It is possible but you need an auxiliary table:
CREATE PROCEDURE procB
AS
declare #table table (CalculatedField1 int, CalculatedField12 int)
insert into #table
EXEC sp_a
select SUM(CalculatedField1), SUM(CalculatedField2)
from #table
GO
This might do what you want:
create table #scratch (CalculatedField1 int, CalculatedField2 int,...)
insert into #scratch (exec procA params)
select sum(CalculatedField1), sum(CalculatedField2),... from #scratch
drop table #scratch
Related
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `sumwhere`(`mus_level` INT) RETURNS int(11)
READS SQL DATA
begin
declare tong int;
select sum(us_id) into tong
from members
where us_level = mus_level
group by us_level;
return tong;
end$$
DELIMITER ;
CREATE FUNCTION FUNC_1_MANV
(
#MANV CHAR(10)
)
RETURNS #TABLE TABLE(HOTEN NVARCHAR(30), CHUCVU NVARCHAR(30))
AS
BEGIN
INSERT INTO #TABLE
SELECT TENNV , CHUCVU
FROM NHANVIEN
WHERE MANV=#MANV
RETURN
END
GO
--THỰC THI
SELECT * FROM dbo.FUNC_1_MANV('NV001')
GO
enter image description here
I want to do the same as below code func "FUNC_1_MANV" but using MySQL.
I want to display one more column of mine, like count(us_id) , or the value of a column (us_id) when I have where run on create function MySQL how. I see MySQL only return 1 parameter.
I'm trying to create a SSIS package where I pull data from an Oracle source, insert into a destination table and run that data against a stored procedure that manipulates the data.
The stored procedure has the following variables:
#ShiftID Varchar (50),
#ProcedureID int,
#Registered int,
#Performed int,
#Deferred int,
#Collected int,
#QNS int,
#Deleted int,
#Intent int,
#APH int,
#ResultError int output,
#ResultMessage varchar(1024) output
And the table I'd like to run the procedure against contain the following columns:
Shift_ID
ProcedureID
Registered
Performed
Deferred
Collected
QNS
Deleted
APH
Right now I have about 500 records in the table and I'd like to run this procedure against all records but I'm not sure how to go about this task.
How can I assign the variables to specific columns in the table and then have it loop or cursor through the entire table?
Thanks,
You can use after Insert trigger for that on the Staging table where you insert rows from your ssis package .
Like this --
CREATE TRIGGER [dbo].[TriggerName] ON [dbo].[yourTableName]
AFTER INSERT
AS
DECLARE #ShiftID VARCHAR(50)
,#ProcedureID INT
,#Registered INT
,#Performed INT
,#Deferred INT
,#Collected INT
,#QNS INT
,#Deleted INT
,#Intent INT
,#APH INT
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT #ShiftID = ins.ShiftID
,#ProcedureID = ins.ProcedureID
,#Registered = ins.Registered
,#Performed = ins.Performed
,#Deferred = ins.Deferred
,#Collected = ins.Collected
,#Pincode = ins.Pincode
,#QNS = ins.QNS
,#Deleted = ins.Deleted
,#Intent = ins.Intent
,#APH = ins.APH
FROM inserted ins
-- TODO: Set parameter values here.
EXECUTE [your Proc Name] #ShiftID
,#ProcedureID
,#Registered
,#Performed
,#Deferred
,#Collected
,#QNS
,#Deleted
,#Intent
,#APH
-- Insert statements for trigger here
END
GO
I have a stored procedure that accepts a string such as A, B, C...etc. I want to split the string and insert each letter as one record into a table. The result should be:
col1 col2
1 A
2 B
3 C
I could use cursor, but cursor is kind of slow if I call this stored procedure from my web page. Is there any better solution?
Instead of passing a comma-separated string, pass a table-valued parameter. First, create a table type in your database:
CREATE TYPE dbo.Strings AS TABLE(String NVARCHAR(32));
Then your stored procedure:
CREATE PROCEDURE dbo.InsertStrings
#Strings dbo.Strings READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Table(Col2) -- assuming col1 is an IDENTITY column?
SELECT String FROM #Strings;
END
GO
Then in your C# code or whatever, you just pass a DataTable as a Structured parameter. Example here and background here.
If you really don't want to do this, because it's too hard or whatever, then you can use a much less efficient string splitting function, e.g.
CREATE FUNCTION [dbo].[SplitString]
(
#List NVARCHAR(MAX),
#Delim VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT [Value] FROM
(
SELECT
[Value] = LTRIM(RTRIM(SUBSTRING(#List, [Number],
CHARINDEX(#Delim, #List + #Delim, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects) AS x
WHERE Number <= LEN(#List)
AND SUBSTRING(#Delim + #List, [Number], LEN(#Delim)) = #Delim
) AS y
);
Then your procedure is:
CREATE PROCEDURE dbo.InsertStrings
#Strings NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Table(Col2) -- assuming col1 is an IDENTITY column?
SELECT [Value] FROM dbo.SplitString(#Strings, ',');
END
GO
I have a table which contains header information for transactions. The transactions belong to different projects.
In the header I have columns:
rhguid - uniqueidentifier
rhserial - int
rh_projectID - int
First I insert the row (there's more columns)
Then I calculate the serial number for that project:
update responseheader
set rhSerial = 1 + (select isnull(max(rhSerial), 0)
from responseheader
where (rhstatus = 0) AND (rh_projectID = 1234))
where
(rhGUID = <preassignedGUID>);
However when there are many transactions happening at the same time for a project I am finding duplicate rhserial values.
I'm doing this in classic ASP with SQL Server 2008.
Is there a better way?
From your example, it doesn't look like you're using a transaction. My guess is that the SELECT portion of the statement is running as READ UNCOMMITTED, otherwise you would not see duplicates. There are ways to start transactions with ADO, but I prefer using stored procedures instead.
Try implementing something like this:
CREATE PROC dbo.ResponseHeader_Insert
<more data to insert>,
#ProjectID INT,
#Status SMALLINT
as
insert responseheader (column names here)
select <param values here>, isnull(max(rhSerial), 0) + 1
from responseheader
where (rhstatus = #Status) AND (rh_projectID = #ProjectID))
If this doesn't work for ya, try creating sequence tables (one for each sequence).
create table <tablename> (
SeqID int identity(1,1) primary key,
SeqVal varchar(1)
)
Create a procedure to get the next identity:
create procedure GetNewSeqVal_<tablename>
as
begin
declare #NewSeqValue int
set NOCOUNT ON
insert into <tablename> (SeqVal) values ('a')
set #NewSeqValue = scope_identity()
delete from <tablename> WITH (READPAST)
return #NewSeqValue
end
If there are too many sequence tables that need to be created or you want to create sequences on the fly, try this approach:
Create table AllSequences (
SeqName nvarchar(255) primary key, -- name of the sequence
Seed int not null default(1), -- seed value
Incr int not null default(1), -- incremental
Currval int
)
Go
create procedure usp_CreateNewSeq
#SeqName nvarchar(255),
#seed int = 0,
#incr int = 1
as
begin
declare #currval int
if exists (
select 1 from AllSequences
where SeqName = #SeqName )
begin
print 'Sequence already exists.'
return 1
end
if #seed is null set #seed = 1
if #incr is null set #incr = 1
set #currval = #seed
insert into AllSequences (SeqName, Seed, Incr, CurrVal)
values (#SeqName, #Seed, #Incr, #CurrVal)
end
go
create procedure usp_GetNewSeqVal
#SeqName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update AllSequences
set #NewSeqVal = CurrVal = CurrVal+Incr
where SeqName = #SeqName
if ##rowcount = 0 begin
print 'Sequence does not exist'
return
end
return #NewSeqVal
end
go
I have a variable table:
DECLARE #A_Table TABLE(ID INT, att1 VARCHAR(100), att2 nvarchar(200))
I want to make dynamic sql, so I insert into this table some data (all inside a loop):
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT ' + #A_Table+ '(ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM '+ #EVEN_OTHER_Table;
EXEC (#sql);
END
sql every time would look like:
INSERT INTO #A_Table SELECT 1 , 'subject', SUM(subject)
INSERT INTO #A_Table SELECT 2 , 'age', SUM(age)
INSERT INTO #A_Table SELECT 3 , 'sex', SUM(sex)....
AND after executing this :
SO I will get:
#A_Table:
id att1 att2
1 subject 4.3
2 age 4.5
3 sex 4.1
but I get an error:
Msg 137, Level 16, State 1, Line 48
Must declare the scalar variable "#A_Table".
SO what is it the syntax to insert dynamically into a variable table?
Ok I have understood it.
You could use the INSERT ... EXEC syntax to insert the data returned by the dynamic SELECT. Of course, you would then need to remove the INSERT part from the dynamic statement.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'SELECT '+CAST(#i AS VARCHAR)+' , ''' + #other_att+''', SUM('+ #other_att + ') FROM '+ #EVEN_OTHER_Table;
INSERT INTO #A_Table (ID,att1,att2)
EXEC (#sql);
END
You have a table variable, not a variable that contains the table name.
So you would need the following.
WHILE (#i <= 100) BEGIN
SELECT #other_att = NAME FROM #other_Table where ID = #i;
SET #sql = 'INSERT INTO #A_Table (ID,att1,att2) SELECT '+CAST(#i AS VARCHAR)+' , '''+ #other_att+''', SUM('+ #other_att') FROM #EVEN_OTHER_Table';
EXEC (#sql);
END
You would also need to declare the table variable as a statement inside the #sql variable, and execute your declare table and inserts together, or use a local/global temporary table.
With a local temporary table (stored in the tempdb) you could do something like this.
CREATE TABLE #testtbl (ID INT);
EXEC ('INSERT INTO #testtbl VALUES (1)');
SELECT * FROM #testtbl
DROP TABLE #testtbl
Some good info about temporary tables in BOL
http://msdn.microsoft.com/en-us/library/ms174979.aspx - quite far down the page
And the table type.
http://msdn.microsoft.com/en-us/library/ms175010.aspx
Your EXEC statement occurs in a different context and is therefore unaware of any variables created in your original context.
To create dynamic insert query it is really a task, I also struggle to find it ,finally I have tried in the following way and it's successfully working. Please find the code below.
CREATE PROCEDURE [dbo].[InsertTodaysData] (#tbl varchar(50),#Days int,
#MDate varchar(50), #EValue varchar(50), #Speed varchar(50),
#Totalreturn varchar(50),#Closingv varchar(50), #TotalReturnV varchar(50))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #SQLQuery varchar(2000)
-- Insert statements for procedure here
set #SQLQuery = 'INSERT INTO '+#tbl+' (ID,MDate,EValue,Speed,TotalReturnRatio,ClosingValue,
TotalReturnValue) VALUES ('+#Days+','''+#MDate+''', '+#EValue+', '+#Speed+',
'+#Totalreturn+', '+#Closingv+', '+#TotalReturnV+')'
EXECUTE(#SQLQuery)
END
Hope this will help you..