Currently I have a static pivot sql query defined in a stored procedure in sql server:
ALTER PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from datetime,
#to datetime
AS
BEGIN
DECLARE #cols nvarchar(12)
DECLARE #query nvarchar(max)
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
FROM (
SELECT ROUND(ds.ct_quot_rate,0) AS Quote,
ROUND(ds.ct_quot_rate,0) AS Quote_Out,
ds.isin
FROM ds
WHERE ds.datum >= #from AND ds.datum <= #to
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(AB000001,
AB000002,
AB000003,
AB000004,
AB000005)
) piv
END
How can I define this static code in dynamic query? I have declared 2 variables.
I think you're after something like this:
ALTER PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from datetime,
#to datetime
AS
BEGIN
DECLARE #cols nvarchar(max)
DECLARE #query nvarchar(max)
SET NOCOUNT ON;
WITH vals AS (
SELECT DISTINCT isin
FROM ds
)
SELECT #cols = COALESCE(#cols + ',','') + '[' + isin + ']'
FROM vals
SET #query = '
SELECT *
FROM (
SELECT ROUND(ds.ct_quot_rate,0) AS Quote,
ROUND(ds.ct_quot_rate,0) AS Quote_Out,
ds.isin
FROM ds
WHERE ds.datum >= #from_param AND ds.datum <= #to_param
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(' + #cols + ' )
) piv'
EXECUTE sp_executesql #query, N'#from_param DATETIME, #to_param DATETIME', #from_param = #from, #to_param = #to
END
CREATE PROCEDURE [dbo].[MonthRepo]
-- Add the parameters for the stored procedure here
#from VARCHAR(20),
#to VARCHAR(20)
AS
BEGIN
IF OBJECT_ID('tempdb..#T') IS NOT NULL
DROP TABLE #T
create table #T
(
datnum varchar(20),
quote INT,
isin VARCHAR(20)
)
insert into #T (datnum,quote,isin)values ('2015-01-01',100,'AB000001'),
('2015-01-01',100,'AB000002'),
('2015-01-02',98,'AB000003'),
('2015-01-02',70,'AB000001'),
('2015-01-03',100,'AB000001')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = Isnull(#columns + ', ', '') + N'[' + tbl.isin+ ']'
FROM (SELECT DISTINCT isin
FROM #T) AS tbl
--SELECT #columns
SELECT #statement = ' SELECT *
FROM (
SELECT ROUND(ds.quote,0) AS Quote,
ROUND(ds.quote,0) AS Quote_Out,
ds.isin
FROM #T ds
WHERE ds.datnum >= CONVERT(datetime,'+''''+#from+''' ,105) AND ds.datnum <= CONVERT(datetime,'''+#to+''' ,105)
) tbl
PIVOT (
COUNT(Quote)
FOR isin IN(' + #columns+ ')) as PVT
'
PRINT #statement
EXEC sp_executesql #statement = #statement
END
EXEC [MonthRepo] #from = '2015-01-01',#to = '2015-01-10'
Related
I have created this stored procedure that works when hard coded
(in the where clause at #WeekStart and #WeekEnd),
If I try to add parameters to the query #WeekStart and #WeekEnd I get the following error:
Must declare the scalar variable "#WeekStart".
My goal is to do do something like this instead of having to hard code it:
exec dbo.GetTotals #WeekStart='2022-04-11',#WeekEnd='2022-04-25'
The stored procedure:
CREATE PROCEDURE [dbo].[GetTotals]
#WeekStart Date,
#WeekEnd Date
AS
begin
set nocount on;
--get row names
DECLARE
#columns NVARCHAR(MAX) = '',
#sql NVARCHAR(MAX) = '';
-- select the category names
SELECT
#columns+=QUOTENAME(DepartmentName) + ','
FROM
DepartmentTable
ORDER BY
DepartmentName;
--set#colums variable
SET #columns = LEFT(#columns, LEN(#columns) - 1);
-- construct dynamic SQL
SET #sql ='
SELECT * FROM
(
select
JobCode,
DepartmentName,
(COALESCE(MonTime, 0)+COALESCE(TueTime, 0)+COALESCE(WenTime, 0)+COALESCE(ThurTime, 0)+COALESCE(FriTime, 0)
+COALESCE(SatTime, 0)+COALESCE(SunTime, 0)) as total
from TimeSheetTable
INNER JOIN DepartmentTable ON TimeSheetTable.DeptId=DepartmentTable.Id
inner join JobCodeTable on TimeSheetTable.JobId=JobCodeTable.Id
--This Works--
-- Where WeekStartDate Between ''2022-04-11'' and ''2022-04-11'' --
--This is throwing an erro--
Where WeekStartDate Between #WeekStart and #WeekEnd
) t
PIVOT(
sum(total)
FOR DepartmentName IN ('+ #columns +')
)pivot_table
ORDER BY JobCode
'
---- execute the dynamic SQL
EXECUTE sp_executesql #sql;
end
exec sp_executesql #Sql, N' #WeekStart Date, #WeekEnd Date', #WeekStart = #WeekStart, #WeekEnd = #WeekEnd
I am trying to loop through a temp table variable that contains a list of table names. I want to simply count the rows in each table where a DateTracked column is greater than 30 days. I am having trouble dynamically changing the FROM #tblName variable to store the record count and then insert it into my tracking table. Eventually I will use a cursor to loop through each, but I just want to get this logic down first for a single table. Here is my test code:
DECLARE #tblName as NVARCHAR(MAX)
DECLARE #q as NVARCHAR(MAX)
SET #q = 'Select Count(DateTracked) FROM Audit.' + #tblName + ' WHERE DateTracked > DATEADD(dd, -30, CAST(GETDATE() as date))'
--DECLARE #tblNameTable TABLE
--(
-- tableName NVARCHAR(MAX)
--)
--INSERT INTO #tblNameTable VALUES (N'myTestTable')
DECLARE #ExpectedRecordsToMove AS TABLE (col1 int)
INSERT INTO #ExpectedRecordsToMove EXECUTE sp_executesql #q, N'#tblName nvarchar(500)', #tblName = 'myTestTable'
SELECT * FROM #ExpectedRecordsToMove
Found solution.
DECLARE #tblName as NVARCHAR(MAX) = 'tblAutoDispatch_DispatchStatus_Map_Tracking'
DECLARE #q as NVARCHAR(MAX) = 'SELECT Count(DateTracked) FROM Audit.' + #tblName + ' WHERE DateTracked > DATEADD(dd, -30, CAST(GETDATE() as date))'
DECLARE #ExpectedRecordsToMove TABLE
(
ExpectedRecordsToMove Int
)
INSERT INTO #ExpectedRecordsToMove
EXECUTE sp_executesql #q
SELECT * FROM #ExpectedRecordsToMove
Note: Answer provided by OP on question.
sp_executesql also allows for output parameters. It is possible to assign variable inside the inner query and return the value.
DECLARE #tblName AS NVARCHAR(MAX) = N'tblAutoDispatch_DispatchStatus_Map_Tracking';
DECLARE #q AS NVARCHAR(MAX)
= N'SELECT #rowcount = COUNT(DateTracked) FROM Audit.' + #tblName
+ N' WHERE DateTracked > DATEADD(dd, -30, CAST(GETDATE() as date))';
DECLARE #rowcount INT;
EXECUTE sp_executesql
#query = #q,
#parameters = N'#rowcount INT OUTPUT',
#rowcount = #rowcount OUTPUT;
SELECT
#rowcount;
You can actually do this without a cursor, by building up the query in one go
You must use QUOTENAME to ensure table names do not cause syntax errors
You cannot parameterize a table name, it must be inserted directly into dynamic SQL
DECLARE #tablenames TABLE (schemaName sysname, tblName sysname);
-- insert schema and table names
DECLARE #sql nvarchar(max) = N'
SELECT
ISNULL(tblName, ''Grand Total'') AS tblName,
SUM(rowcount) AS rowcount
FROM (
' +
(
SELECT STRING_AGG(CAST(
N' SELECT ' + QUOTENAME(tn.schemaName, '''') + N'.' + QUOTENAME(tn.tblName, '''') + N' AS tblName,
Count(DateTracked) AS rowCount
FROM ' + QUOTENAME(tn.schemaName) + N'.' + QUOTENAME(tn.tblName) + N'
WHERE DateTracked > DATEADD(dd, -30, CAST(GETDATE() as date))'
AS nvarchar(max)), N'
UNION ALL
')
FROM #tablenames tn
JOIN sys.tables t ON tn.schemaName = SCHEMA_NAME(t.schema_id) AND tn.tblName = t.name
) + N'
) AS tables
GROUP BY ROLLUP(tblName);
';
PRINT #sql; -- for testing
EXEC (#sql);
If you don't have STRING_AGG on your version of SQL Server, you must use FOR XML instead
There is no problem for me to pivot statistic columns in my query e.g Column 1 , Column 2 , Column 3.... and so on.
But i would like to do this dynamic instead.
My data looks like this:
i want to be able to EXECUTE a store procedure to get the output result:
Exec sp_output 1 (from another window where '1' represents the PoolID (#AppPool)) to look like this:
This is my SP:
create PROCEDURE [dbo].[sp_test]
#Query as nvarchar(100) -- OUTPUT?,
#AppPool AS nvarchar(50)
AS
SELECT #Query = Attribute FROM [dbo].[Vy_UserAccess] WHERE PoolID = #AppPool
SELECT [Users],'+ #Query +' FROM
(SELECT [Pool],[Users],[RecNum],[Attribute],[Values] FROM [dbo].[Vy_UserAccess] ) AS T1
PIVOT (MAX([Values]) FOR [ATTRIBUTE] IN ('+ #Query +')) AS T2
Is this possible to achieve by just fine tuning my code or do i have to go on another direction?
You can do It in following:
QUERY
CREATE PROCEDURE [dbo].[sp_test]
#AppPool AS NVARCHAR(60)
AS
DECLARE #cols AS NVARCHAR(MAX) = '',
#sql AS NVARCHAR(MAX)
SELECT #cols += QUOTENAME([Name]) + ','
FROM (SELECT DISTINCT Attribute as Name
FROM [dbo].[Vy_UserAccess]
WHERE PoolID = #AppPool
) a
ORDER BY Name DESC
SET #cols = LEFT(#cols, LEN(#cols) - 1)
SET #sql = 'SELECT Users, ' + #cols + ' FROM
(
SELECT [Pool],[Users],[RecNum],[Attribute],[Values]
FROM [dbo].[Vy_UserAccess]
) AS T1
PIVOT (MAX([Values]) FOR [ATTRIBUTE] IN ('+ #cols +')) AS T2'
EXEC sp_executesql #sql, N'#AppPool NVARCHAR(60)', #AppPool
EXECUTION
Exec sp_test 1
QUERY WITH SAMPLE DATA
CREATE PROCEDURE sp_test
#AppPool AS NVARCHAR(60)
AS
CREATE TABLE #test
(
PoolId NVARCHAR(60),
Pool NVARCHAR(40),
Users NVARCHAR(60),
RecNum INT,
Attribute NVARCHAR(40),
[Values] NVARCHAR(20)
)
INSERT INTO #test VALUES
('1', 'FINANCE', 'User1', 2, 'DIVISION', '010'),
('1', 'FINANCE', 'User1', 1, 'COMPANY', '1'),
('1', 'FINANCE', 'User1', 1, 'DIVISION', '050')
DECLARE #cols AS NVARCHAR(MAX) = '',
#sql AS NVARCHAR(MAX)
SELECT #cols += QUOTENAME([Name]) + ','
FROM (SELECT DISTINCT Attribute as Name
FROM #test
WHERE PoolID = #AppPool
) a
ORDER BY Name DESC
SET #cols = LEFT(#cols, LEN(#cols) - 1)
SET #sql = 'SELECT Users, ' + #cols + ' FROM
(
SELECT [Pool],[Users],[RecNum],[Attribute],[Values]
FROM #test
) AS T1
PIVOT (MAX([Values]) FOR [ATTRIBUTE] IN ('+ #cols +')) AS T2'
EXEC Sp_executesql #sql, N'#AppPool NVARCHAR(60)', #AppPool
DROP TABLE #test
OUTPUT
Users DIVISION COMPANY
User1 050 1
User1 010 NULL
I am using CTE like below... But I am getting an error like
No column name was specified for column 1 of 'TempResult'.
Also here I am passing #Query from another stored procedure, and in this procedure I need to execute that #Query inside CTE TempResult.
CREATE PROCEDURE [dbo].[SelectAllProjectPaging]
#CurrentPage int,
#RecordsPerPage int,
#Column varchar(50),
#Query nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #query nvarchar(max)
SET #query = 'ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,' + #Query
-- Insert statements for procedure here
DECLARE #FirstRecord int, #LastRecord int
SELECT #FirstRecord = (#CurrentPage - 1) * #RecordsPerPage
SELECT #LastRecord = (#CurrentPage * #RecordsPerPage + 1);
WITH TempResult as
(
Select #query
)
SELECT TOP (#LastRecord - 1) *
FROM TempResult
WHERE RowNumber > #FirstRecord
AND RowNumber < #LastRecord;
SELECT COUNT(*) as count
FROM ProjectList
End
You need to make the entire query with dynamic sql. something like this:
SET #query= 'WITH TempResult as
(
SELECT + ' + #query +
')
SELECT TOP (' + CAST((#LastRecord - 1) AS VARCHAR(20)) +
') * FROM TempResult
WHERE RowNumber > ' + CAST(#FirstRecord AS VARCHAR(20)) +
' AND RowNumber < ' + CAST(#LastRecord AS VARCHAR(20)) + '; '
EXECUTE #query
Edit
To the comment. Yes it should select what I can see. The #query is equals to:
set #query = 'ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,'+ #query
Then you will need:
SELECT ' ROW_NUMBER() OVER(ORDER BY ProjectList.ProjectId DESC) as RowNumber,' + #query
Your "With TempResult As" has to be extended a bit, containing the column names to be used.
Example
With TempResult (column1, column2, column3) as
(
select #query
)
Ref:
WITH expression_name [ ( column_name [,...n] ) ]
AS
( CTE_query_definition )
From http://technet.microsoft.com/en-us/library/ms190766%28v=sql.105%29.aspx
the results look like this but wher the column name says 'Today' I want it to be todays date.
Try this technique:
declare #dt datetime
declare #sql varchar(100)
set #dt = getdate()
set #sql = 'select 1 as [ ' + convert( varchar(25),#dt,120) + ']'
exec (#sql)
In your Case:
declare #dt datetime
declare #sql varchar(100)
set #dt = getdate()
set #sql = 'select 0 as [ ' + convert( varchar(25),#dt,120) + ']'
exec (#sql)
I would return an integer representing a day offset and parse it in the client, failing that you are going to have to use dynamic SQL or do something with the underlying column name itself;;
declare #sql nvarchar(128) = '
select
col1,
col2,
0 as [' + cast(getdate() as nvarchar(32)) + ']
from T'
exec(#sql)
Or
--today
declare #now varchar(32) = cast(getdate() as varchar(32))
--result to temp table
select col1, col2, 0 as [Now] into #T from TheTable
--rename col
exec tempdb..sp_rename '#T.Now', #now, 'COLUMN'
--select
select * from #T