Dynamic query based on datetime parameter - sql

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

Related

dynamic pivot with parameter passed in

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

Selecting multiple database tables from between datetime

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

SQL Server 2008 ALTER TABLE add column with specific column

Is there any way I can add a column to a table but I want the heading to be a date, and every new column added will have a column heading for the next day hence the
SET #date1 = #date1 + 1
What I want the table to look like is, where the date on top is a new column for each day the script loops:
StoreID StoreName 02/01/12 03/01/12 04/01/12
1234 Coles1 7512 8574
1235 Coles2 7210 8441
1236 Coles3 4845 5448
When I run the script I get the following error messages:
Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '#Column'.
Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '#Column'.
Here is my script:
DECLARE #date datetime
DECLARE #date1 datetime
DECLARE #date2 datetime
DECLARE #Column varchar(8)
SET #date = '02 Jan 2012'
SET #date1 = '02 Jan 2012'
SET #date2 = '08 Jan 2012'
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans')
BEGIN
CREATE TABLE #vl_temp_trans
(StoreID INT,
StoreName VARCHAR(100),
#Column MONEY) ----> column name to be date "#Column)
END
WHILE (#date1 <= #date2)
BEGIN
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
ALTER table #vl_temp_trans
ADD #Column MONEY ----> column name to be date "#Column"
Insert into #vl_temp_trans (storeID, storeName, #Column)
select storeId, storeName, TotalDailyTransactions
from daily_trans t1 (nolock)
full outer join outlets t2 (nolock) on t1.StoreID = t2.StoreID
where DailyEnd = #date1 + 1
SET #date1 = #date1 + 1
END
You can't do this without dynamic SQL. Here is a query that will get you the result you want. You are more than welcome to uncomment the --INTO #t bit, however it is unclear what you want to do with the #temporary table beyond that (if you tell us the end result, instead of "I want to add a column name as #column, maybe we can help with that too). In order to continue referencing that #t table, you'll need to continue using code within the same scope - meaning more dynamic SQL that is executed within the same sp_executesql call.
DECLARE
#start DATE = '2012-01-02',
#end DATE = '2012-01-08';
DECLARE
#sql NVARCHAR(MAX) = N'',
#colMax NVARCHAR(MAX) = N'',
#colNames NVARCHAR(MAX) = N'';
;WITH x(rn) AS ( SELECT TOP (DATEDIFF(DAY, #start, #end) + 1) ROW_NUMBER()
OVER (ORDER BY [object_id]) - 1 FROM sys.all_columns ),
y(d) AS ( SELECT CONVERT(CHAR(10), DATEADD(DAY, rn, #start)) FROM x
)
SELECT #colMax += N',' + CHAR(13) + CHAR(10)
+ QUOTENAME(d) + ' = SUM(CASE WHEN DailyEnd = '''
+ d + ''' THEN TotalDailyTransactions ELSE 0 END)',
#colNames += N',' + QUOTENAME(d) FROM y;
SET #sql = 'SELECT StoreID, StoreName, ' + STUFF(#colNames, 1, 1, '')
+ ' --INTO #t
FROM ( SELECT StoreID, StoreName, ' + STUFF(#colMax, 1, 1, '')
+ ' FROM dbo.daily_trans
WHERE DailyEnd >= ''' + CONVERT(CHAR(10), #start) + ''''
+ ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, #end)) + '''
GROUP BY StoreID, StoreName
UNION ALL SELECT StoreID, StoreName, ' + STUFF(#colMax, 1, 1, '')
+ ' FROM dbo.outlets
WHERE DailyEnd >= ''' + CONVERT(CHAR(10), #start) + ''''
+ ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, #end)) + '''
GROUP BY StoreID, StoreName) AS x';
PRINT #sql;
-- EXEC sp_executesql #sql;
I think the problem is that you can't use a variable to define a column name.
I used some of your code to test with. This first part executed fine.
DECLARE #date1 datetime
DECLARE #Column varchar(8)
SET #date1 = '02 Jan 2012'
SET #Column = CONVERT(VARCHAR(8), #date1, 3)
select #Column
But when I added the CREATE TABLE statement and executed all of it at once, then I got the same error you did.
CREATE TABLE #vl_temp_trans
(StoreID INT,
StoreName VARCHAR(100),
#Column MONEY) ----> column name to be date "#Column)
To do this you will need to build up the CREATE TABLE and ALTER TABLE statements as a string and then execute those using EXECUTE or sp_executesql. A search for "dynamic sql" will also give you some article that describe this too.
There is two things you need to do to execute this code...
Create dynamic sql make use of SP_ExecuteSQl
you need to make your temp table Gobal because when you create private temp table it remain in scope of dyanic sql sp only
have look to below code which is updated by me sure reslove your issue
DECLARE #date datetime
DECLARE #date1 datetime
DECLARE #date2 datetime
DECLARE #ColumnNAAME varchar(8)
Declare #Query NVARCHAR(1000)
DECLARE #ParmDefinition NVARCHAR(500);
SET #date = getdate()
SET #date1 = getdate()
SET #date2 = getdate()
SET #ColumnNAAME = CONVERT(VARCHAR(8), #date1, 3)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans')
BEGIN
SET #ParmDefinition = N'#Column varchar(8)';
Set #Query = 'CREATE TABLE ##vl_temp_trans (StoreID INT, StoreName VARCHAR(100), ['+#ColumnNAAME+'] MONEY)'
EXECUTE sp_executesql #Query,#ParmDefinition,
#Column = #ColumnNAAME;
----> column name to be date "#Column)
SELECT * from ##vl_temp_trans
END
ELSE
BEGIN
SELECT * from ##vl_temp_trans
END

How do I name a column as a date value

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

SQL Server 2008 Dynamic Query using CTE

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.