I am trying to write a Dynamic Query which uses a CTE. But I am facing problems - see below
This is a simplified case
declare #DynSql varchar(max)='';
declare #cnt as integer;
with months as (
select CAST('07/01/2010' as DATE) stdt
UNION ALL
SELECT DATEADD(MONTH,1,STDT) FROM months
WHERE DATEADD(MONTH,1,STDT)<CAST('06/30/2011' AS DATE)
)
select COUNT(*) from months
set #DynSql='select * from months'
exec (#DynSql)
This does not work - the error I get is
Invalid Object name 'Months'
Is there any way of achieving what I want. Will it work if I use Temp table or table variable.
Your dynamic SQL cannot reference months. The scope of a CTE is a single statement:
with cte as (cte definiton) select from cte;
If you want to re-use the CTE's result or definition, you have to either re-define the CTE every time you want to use it (eg. in the #DynSql) or materialize it's result into a table #variable and re-use the table #variable.
The with keyword does not declare an object that can be referenced in later queries. It is part of the select query. Your dynamic sql was trying to reference an object months that did not exist. Include the CTE in the string defining the dyanic query.
declare #DynSql varchar(max)='';
set #DynSql=
'with months as (
select CAST(''07/01/2010'' as DATE) stdt
UNION ALL
SELECT DATEADD(MONTH,1,STDT) FROM months
WHERE DATEADD(MONTH,1,STDT)<CAST(''06/30/2011'' AS DATE))
select * from months'
exec (#DynSql)
However, I don't see what you gain by making the SQL dynamic, since nothing within the SQL statement varies.
If you want an object you can reference later, you could create a view (once) that would be used by your dynamic query, and similar queries (many times).
create view months_v as
with months as (select CAST('07/01/2010' as DATE) stdt
UNION ALL
SELECT DATEADD(MONTH,1,STDT) FROM months
WHERE DATEADD(MONTH,1,STDT)<CAST('06/30/2011' AS DATE))
select * from months;
go
declare #DynSql varchar(max)='';
set #DynSql='select * from months_v'
exec (#DynSql)
Well I got it to work, but I do not understand the scope of this...
declare #DynSql varchar(max)
declare #cnt as integer;
declare #stdt datetime;
Set #DynSql =''
Select #stdt = CAST('07/01/2010' as DATEtime);
with months as (
SELECT DATEADD(MONTH,1,#stdt) As [month] WHERE DATEADD(MONTH,1,#stdt)<CAST('06/30/2011' AS DATEtime)
)
select COUNT(*) from months
Revision now that I have move information:
declare #DynSql varchar(max)
declare #cnt as integer;
declare #stdt datetime;
Set #DynSql = 'With ctemonths as ('
Select #stdt = CAST('07/01/2010' as DATEtime);
Set #cnt = 1;
while #cnt <= 11 --(Select DateDiff(mm, #stdt, '06/30/2011'))
Begin
IF (#CNT =1)
Set #DynSql = #DynSql + 'Select DATEADD(MONTH,' + Cast(#cnt as nvarchar(2)) + ',''' + Convert(varchar(10), #stdt, 103) + ''') As [month] '
eLSE
Set #DynSql = #DynSql + 'UNION Select DATEADD(MONTH,' + Cast(#cnt as nvarchar
(2)) + ',''' + Convert(varchar(10), #stdt, 103) + ''') As [month] '
Set #cnt = #cnt + 1
End;
Set #DynSql = #DynSql + ') Select * from ctemonths' -- PIVOT (max([month]) for [month] in ([month]))'
exec (#DynSql)
You can't use that CTE or #TableVariable in a dynamic sql, but you can use a #Temp table for this. Create a temp table, store the data in that ( u can copy your CTE result to temp table) and use it in dynamic query. That is the solution.
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 have a SQL Server database with date representation name like below & each database contains table A (table A having column like id, datetime, value, value1 etc).
Jan2018
Feb2018
Mar2018 and so on..
My search condition is user selected date (eg. from 01-Jan-2018 to 01-Jun-2018) which I am passing to a stored procedure (max range 6 month). I want to generate dynamic query to get data from these database based on datetime passed.
How to achieve this functionality as I found difficult to implement.
Can you try this query
CREATE PROCEDURE Myproc #FromDate DATE,
#ToDate DATE
AS
BEGIN
DECLARE #SQL NVARCHAR(max)='',
#unionall VARCHAR(10)=''
WITH cte
AS (SELECT #FromDate dt,
1 mont
UNION ALL
SELECT Dateadd(month, 1, dt) dt,
mont + 1 mont
FROM cte
WHERE mont < Datediff(month, #FromDate, #ToDate)
)
SELECT #SQL += #unionall + '
select * from ['
+ LEFT (CONVERT(VARCHAR, Datename (month, dt )), 3)
+ CONVERT (VARCHAR, Year (dt))
+ '].[dbo].[tablename]',
#unionall = ' union all '
FROM cte
PRINT #SQL
EXECUTE( #SQL)
END
You should query sys.databases to find a database you need.
Then, as you can only use static declarations of databases, you should create a textual select statement and execute it.
I tried it on my dbs and it worked.
This is my code:
declare #date varchar(20) = '2018'
declare #dbName varchar(20)
declare #sSql varchar(200)
declare #sConditions varchar(20) = ''
Set #dbName = (SELECT name FROM master.sys.databases
where name like '%' + #date + '%')
print #dbName
Select #sSql = 'Select * From ' + #dbName + '.dbo.MyDB '
--+ ' Where ' + #sConditions
Execute (#sSql)
if you need to query all that fit year. do like this:
declare #date varchar(20) = 'a'
SELECT name Into #dbnames
FROM master.sys.databases
where name like '%' + #date + '%'
this brings a table of all sutable dbs. then query each one of them using loop. like cursor
Are you looking for
CREATE PROCEDURE MyProc
#FromDate DATE,
#ToDate DATE,
#Target SysName
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX)= N'SELECT * FROM [' +
#Target +
'] WHERE [Dates] >= #FromDate AND [Dates] <= #ToDate';
EXECUTE sp_executesql #SQL,
N'#FromDate DATE, #ToDate DATE',
#FromDate,
#ToDate;
END
Demo
As I now understand what you are trying to do, you can
CREATE PROCEDURE ProcName
#FromDate DATE,
#ToDate DATE
AS
BEGIN
--Declare a variable to hold the Dynamic SQL
DECLARE #SQL NVARCHAR(MAX) = N'';
--Generate the databases names
WITH CTE AS
(
SELECT #FromDate D,
1 N
UNION ALL
SELECT DATEADD(Month, N, #FromDate),
N + 1
FROM CTE
WHERE N <= DATEDIFF(Month, #FromDate, #ToDate)
)
--Build the SELECT statement
SELECT #SQL = #SQL+
N'SELECT * FROM ['+
CONVERT(VARCHAR(3), D, 100)+
CAST(YEAR(D) AS VARCHAR(4))+
'].dbo.TableName UNION ALL ' --Or UNION as you want
FROM CTE;
--Remove the last UNION ALL
SET #SQL = LEFT(#SQL, LEN(#SQL) - 10); --If UNION then just -6
--Execute the statement
EXECUTE sp_executesql #SQL;
END
I need some help with using a cursor and variable to populate a query. I am using SQL Server 2008 R2.
What I am trying to do is populate a temp table with inserts, run through the one column of data to generate a variable that will then populate a query that will check the number of rows in a table. Here is what I have so far:
IF OBJECT_ID('tempdb..#part_tables') IS NOT NULL DROP TABLE #part_tables
create table #Part_tables
(table_Name nvarchar(100))
Insert INTO #Part_Tables (table_name)
SELECT [InstancesTable] FROM [BAMPrimaryImport].[dbo].[bam_Metadata_Partitions]
WHERE [ArchivingInProgress]=0 and ArchivedTime IS NULL
and creationtime < dateadd(DD,-21,getdate())
GO
Insert INTO #Part_Tables (table_name)
SELECT [RelationshipsTable] FROM [BAMPrimaryImport].[dbo].[bam_Metadata_Partitions]
WHERE [ArchivingInProgress]=0 and ArchivedTime IS NULL
and creationtime < dateadd(DD,-21,getdate())
GO
DECLARE #count_query VARCHAR(MAX)
DECLARE #Value NVARCHAR(100)
SET #Value ='Select Table_Name from #Part_Tables'
SET #count_query ='
select count (*) from #Value with (NOLOCK)'
WHILE 1 = 1
BEGIN
EXEC(#count_query + ' option(maxdop 5) ')
IF ##rowcount < 1 BREAK;
END
If this will work, great! If you have a different / better way to do it, I would appreciate any guidance that someone could offer.
Here is a much simpler way to get the row counts from those tables. No need for cursors or while loops. And be careful with that NOLOCK hint...it can do a lot more than just dirty reads. http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select count(*) from ' + QUOTENAME(InstancesTable) + ' UNION ALL '
FROM [BAMPrimaryImport].[dbo].[bam_Metadata_Partitions]
WHERE [ArchivingInProgress] = 0
and ArchivedTime IS NULL
and creationtime < dateadd(Day, -21, getdate())
set #SQL = LEFT(#SQL, len(#SQL) - 10)
select #SQL --uncomment exec statement below when satisfied this is correct
--exec sp_executesql #SQL
I want to select a database table between the range of the date selected from the datepicker on my web, my sample database table names are:
output_11FEB2016
output_13FEB2016
output_15FEB2016
output_21FEB2016
I want to select tables to show and show their contents on my web, here is my current codes from what I understand on my research.
ALTER PROCEDURE [dbo].[gen048_mLIST]
-- Add the parameters for the stored procedure here
#gfromDate varchar(10),
#gtoDate varchar(10)
AS
SET NOCOUNT ON
declare #sql varchar(5000)
set #sql='select * output_'
if(#gfromDate<>'' and #gtoDate<>'')
begin
set #sql=#sql+'between '+convert(datetime,'''+#gfromDate+''')+' and '+convert(datetime,'''+#gtoDate+''')+' '
--print #sql
exec(#sql)
-- [dbo].[gen048_mLIST] '2-16-2016','2-18-2016'
END
Sorry for my messed up codes and explanation, I appreciate those who can help me figure out my problem.
You will have to select the rows from multiple tables,UNION it and display it in your application.I've used hardcoded dates to generate the SQL but you can modify/extend this to suit your requirements.
declare #gfromDate varchar(10) = '11/02/2016'
declare #gtoDate varchar(10) = '24/02/2016'
declare #fromDate datetime
declare #toDate datetime
declare #totaldays int
set #fromDate = (select convert (date, #gfromDate, 104))
set #toDate = (select convert (date, #gtoDate, 104))
-- get total number of days between from and to dates
set #totaldays = (select datediff(day,#fromdate,#toDate))
declare #sql varchar(max) = ''
declare #tablename varchar(20)
declare #counter int = 1
-- generate the sql to get data from the tables within a date range
while #counter < #totaldays
begin
set #tablename = (select convert(varchar(11), #fromDate, 106))
set #tablename = replace(#tablename,' ','')
-- check if table exists
--if object_id(#tablename, 'U') is not null
--begin
set #sql = #sql + 'select * from output_' + #tablename
if(#counter < #totaldays-1)
begin
set #sql = #sql + ' union '
end
set #fromDate = dateadd(day,1,#fromDate)
set #counter = #counter + 1
--end
end
print #sql
SQL Generated
select * from output_11Feb2016 union
select * from output_12Feb2016 union
select * from output_13Feb2016 union
select * from output_14Feb2016 union
select * from output_15Feb2016 union
select * from output_16Feb2016 union
select * from output_17Feb2016 union
select * from output_18Feb2016 union
select * from output_19Feb2016 union
select * from output_20Feb2016 union
select * from output_21Feb2016 union
select * from output_22Feb2016
I need to run multiple select count queries to count how many people are available at certain times through the day to plot into a table from ms sql server.
I have the below sql which works, but is returning each count as a new table, I would like them to all in one table on different columns.
DECLARE #Day varchar(max)
SET #Day = 'Sunday'
DECLARE #Provider varchar(max)
SET #Provider = '58611'
DECLARE #sqlText varchar(max);
SET #sqlText = N'SELECT COUNT(*) AS Available0700
FROM tblCarersRota INNER JOIN tblCarersProviders ON tblCarersProviders.CarerID = tblCarersRota.CarerID
WHERE Rotation = 2 AND tblCarersProviders.ProviderID = '''+ #Provider + ''' AND ''07:00'' between ' + #Day + 'StartTime AND ' + #Day + 'EndTime '
Exec (#sqlText)
SET #sqlText = N'SELECT COUNT(*) AS Available0800
FROM tblCarersRota INNER JOIN tblCarersProviders ON tblCarersProviders.CarerID = tblCarersRota.CarerID
WHERE Rotation = 2 AND tblCarersProviders.ProviderID = '''+ #Provider + ''' AND ''08:00'' between ' + #Day + 'StartTime AND ' + #Day + 'EndTime '
Exec (#sqlText)
Actual current result:
Available0700
21
Available0800
22
Desired result:
Available0700 || Available0800
21 || 22
I have looked at where you select (select query 1) (select query 2) but I can't get that to work with the dynamic sqltext.
How can I modify my selects to get them to all return as 1 table?
Thanks
Option 1, put it in 2 rows with UNION ALL:
SELECT COUNT(*) as Counts, 'Available0700' AvailableTime
FROM ...
UNION all
SELECT COUNT(*) as Counts, 'Available0800' AvailableTime
FROM ...
Option 2, in 2 columns with subqueries:
SELECT (SELECT COUNT(*) FROM ...) as Available0700,
(SELECT COUNT(*) FROM ...) as Available0800
I think you can store these values in variables and finally select these variables in your select query.
Below is an example code in which i have used a table variable to execute the dynamic queries and store the records and finally used a PIVOT query to fetch the require output.
DECLARE #tablevar TABLE
(
Query VARCHAR(100),
Cnt INT
)
DECLARE #sqlText varchar(max)
SET #sqlText = N'SELECT ''Available Value 1'', 100 '
INSERT INTO #tablevar
Exec (#sqlText)
SET #sqlText = N'SELECT ''Available Value 2'', 200 '
INSERT INTO #tablevar
Exec (#sqlText)
SET #sqlText = N'SELECT ''Available Value 3'', 300 '
INSERT INTO #tablevar
Exec (#sqlText)
SELECT * FROM #tablevar
PIVOT(SUM(Cnt) FOR Query IN([Available Value 1], [Available Value 2], [Available Value 3])) AS PIV
Above code is an example, please replace it with your actual code accordingly.
Thanks
Why did you use dynamic query? You can use case when inside operator COUNT in such way: COUNT(CASE WHEN <yours filter with time 7.00 > then 1 else null end) AS Available0700 , COUNT(CASE WHEN <yours filter with time 8.00 > then 1 else null end) AS Available0800.