SQL Select maxDate in SP - sql

USE [MyDatabase]
GO
Object: StoredProcedure [dbo].[SP_MyProcedure]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[SP_MyProcedure]
-- Add the parameters for the stored procedure here
#StartDate NVARCHAR(19),
#EndDate NVARCHAR(19)
AS
BEGIN
SET NOCOUNT ON;
Insert statements for procedure here
DECLARE #FirstQuery nvarchar(1500);
DECLARE #SecondQuery nvarchar(1500);
DECLARE #TSQL nvarchar(4000);
SET #FirstQuery =
'
SELECT * FROM OPENQUERY(LinkedServer,
''
SELECT * FROM Server.Table
WHERE Name IN
(SELECT Tagname COLLATE DATABASE_DEFAULT FROM LocalServer.MyServer.dbo."NameList"
WHERE LOCATION = ''''X'''' AND SOURCE = ''''Y'''') AND TIMESTAMP >= ''''' + #StartDate + ''''' AND TIMESTAMP < ''''' + #EndDate + ''''''')';
My question is: How could I include max(date) in the code, so the #startDate would be compared to the latest available date for a column in the DB instead of todays date.
The code you see works fine, however when I choose a later date than the last existing date in the DB the query runs for a while before it returns an error that no columns were found.
Thanks in advance for any suggetions.
HELP.
The following part of the code doesn't work, but I can't figure out why. Does anyone have any suggestions? Thank you
-- Insert statements for procedure here
DECLARE #FirstQuery nvarchar(1500);
DECLARE #SecondQuery nvarchar(1500);
DECLARE #TSQL nvarchar(4000);
DECLARE #MaxTimeStamp nvarchar(19);
SET#MaxTimeStamp =
'SELECT MAX(TimeStamp) From OPENQUERY(LinkedServer)'
IF #StartDate <= #MaxTimeStamp
BEGIN
SET #FirstQuery =
'
SELECT * FROM OPENQUERY(LinkedServer,
''
SELECT * FROM Server.Table
WHERE Name IN
(SELECT Tagname COLLATE DATABASE_DEFAULT FROM LocalServer.MyServer.dbo."NameList"
WHERE LOCATION = ''''X'''' AND SOURCE = ''''Y'''') AND TIMESTAMP >= ''''' + #StartDate + ''''' AND TIMESTAMP < ''''' + #EndDate + ''''''')';
END

Well, you could replace it with a subquery:
(select max(timestamp) from NameList)
If this is a stored procedure, you might want to put this in a variable, something like:
declare #MaxTimestamp datetime;
select #MaxTimestamp = max(TimeStamp) from NameList
-- in your query, something like
coalesce(#StartTime, maxTimeStamp)
If performance is an issue, try adding an index on NameList(Location, Source, Timestamp).

Try this...
DECLARE #maxDate datetime;
SELECT #maxDate = MAX(timestamp) FROM OPENQUERY(...);
IF #StartDate <= #maxDate
BEGIN
--Your original query here
END

Related

Dynamic SQL DateTime comparison while data archive is not working

I have written this stored procedure for data purge from one of my tables. I have made it configurable to either archive the data or do a hard delete. Since the volume of data is quiet large, i am using loops to do the same.
The delete part of it is working fine However the archive part of it is giving me hard times and i am kind of stuck there with multiple tries.
Here is my SP.
ALTER PROCEDURE [dbo].[spPurgeRecords_new] (
#Age AS INT,
#NumberOfLoops AS BIGINT,
#DeleteSize BIGINT,
#IsArchive BIT
)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN
DECLARE #CurrentLoop AS BIGINT;
SET #CurrentLoop = 0
declare #cutoffDate datetime;
declare #maxXDate datetime;
declare #loop varchar(50);
select #cutoffDate = dateadd(year,-#Age,getdate())
select #maxXDate = max(dateCreated) from cbr_audit where dateCreated < #cutoffDate
declare #date varchar(100), #cmd varchar(1000),#archivedate varchar(100)
set #date = (select FORMAT(getdate(), 'yyyyMMdd'));
set #archivedate = (select FORMAT(#maxXDate, 'yyyyMMdd'));
declare #backupTable varchar(100)
set #backupTable = 'cbr_audit_Backup_' + #date;
BEGIN TRY
BEGIN TRANSACTION
WHILE #CurrentLoop < #NumberOfLoops
BEGIN
IF #IsArchive = 1
BEGIN
--Archive the records into a backup table
IF OBJECT_ID (#backupTable, N'U') IS NULL
begin
set #cmd = 'SELECT * INTO [cbr_audit_Backup_'+ #date +'] FROM [cbr_audit] WITH (NOLOCK) where convert(datetime,dateCreated,101) <= CONVERT(DATETIME, ''' + #archivedate + ''', 101)'
exec(#cmd)
end
--Delete the rows from cbr_audit table
DELETE
FROM dbo.cbr_audit
WHERE id IN
(SELECT TOP(#DeleteSize) id
FROM dbo.cbr_audit WITH (NOLOCK)
WHERE dateCreated <= #maxXDate);
END
ELSE
BEGIN
-- Delete the records
DELETE
FROM dbo.cbr_audit
WHERE id IN
(SELECT TOP(#DeleteSize) id
FROM dbo.cbr_audit WITH (NOLOCK)
WHERE dateCreated <= #maxXDate);
END
-- WAITFOR DELAY '00:00:00:500';
SET #CurrentLoop = #CurrentLoop + 1;
set #loop = cast(#currentloop as varchar(50))
RAISERROR (#loop, 0, 1) WITH NOWAIT
END
COMMIT TRANSACTION
END TRY
BEGIN CATCH
--Rollback
RETURN
END CATCH
END
In This SP, in the archive part of code the dynamic sql is not giving any results. DateCreated is of Datetime type. Can someone please help me on this.
Thanks in Advance.
Seems that you are using SQL 2016 or above, try CONCAT, something like:
select concat('SELECT * INTO [cbr_audit_Backup_', #date,'] FROM [cbr_audit] WITH (NOLOCK) where convert(datetime,dateCreated,121) <= ''', CONVERT(varchar(30), #archivedate , 121), '''')
few more things:
I strongly recommend you always to use style 121 (canonical)
or 126 (ISO8601) so you'll SQL will not be confused by mm/dd/yyyy (101) or dd/mm/yyyy (103).
you are deleting by chunks, but the transaction is for all the block. consider doing only transaction for each delete (implicit)
instead insert into and then delete, have a look to OUTPUT clause to DELETE here

Create a new table every time though a stored procedure

I want create a new table every time though a stored procedure.
declare #datetime datetime
declare #date varchar(20)
select #datetime = (GETDATE() - 1)
select #date = convert(varchar(10), #datetime, 112)
print #datetime
print #date
create table #businessmster+'_'+#date
(
contentid int
)
Table name which I want is #businessmaster_20171103
You can use this query.
Declare #strTableName varchar(500)
SET #strTableName = 'create table businessmster_' + #date +'( contentid int )
GO
INSERT INTO businessmster_' + #date +' Select Field FROM <<YourTable>> WHERE <<Condition>>
GO'
Print #strTableName
Exec(#strTableName)
You can use dynamic query as:
DECLARE #TableName NVARCHAR(MAX);
SET #TableName = N'CREATE TABLE businessmaster_'+
CONVERT(VARCHAR(10),GetDate()-1,112)+
N' ( contentid int )';
SELECT #TableName
EXEC(#TableName);
According to your comment I remove the # symbol.

Create snapshot tables on first day of month with date in tablename - stored procedure

I am trying to create an stored procedure in SQL Server that should check current date: if today is the first day of month then create some tables and include yesterday date in the table name. If today is not the first day of month, then do nothing.
The idea qould be to simply call this stored procedure in a daily SSIS package.
I am struggling with the addition of the "else (do nothing" and adding the previous date to the table name.
Would something like this work? I can't get it to compile...
DECLARE #d CHAR(10) = CONVERT(CHAR(8), dateadd(day,-1,GETDATE()), 112)
IF DAY(GETDATE())=1
BEGIN
DECLARE #table1name NVARCHAR(MAX) = CONCATENATE('snapshots_db.Table1_',#d);
select *
into #table1name
from sales_db.Table1;
DECLARE #table2name NVARCHAR(MAX) = CONCATENATE('snapshots_db.Table2_',#d);
select *
into #table2name
from sales_db.Table2;
END
ELSE
BEGIN
1=1
END
your code seems to be with the logic you are trying to achieve. for the 'ELSE nothing' part, you can just literally do nothing, don't use any code in that section. I formatted your query above so you could check each section clearly.
DECLARE #d CHAR(10),
#table1name NVARCHAR(MAX),
#table2name NVARCHAR(MAX);
SET #d = CONVERT(CHAR(8), dateadd(day,-1,GETDATE()), 112);
SET #table1name = CONCATENATE('snapshots_db.Table1_',#d);
SET #table2name = CONCATENATE('snapshots_db.Table2_',#d);
IF DAY(GETDATE())=1
BEGIN
SELECT *
INTO #table1name
FROM sales_db.Table1;
SELECT *
INTO #table2name
FROM sales_db.Table2;
END;

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

Find a dynamic database name in a view

In a SQL server database I have have this kind of table :
EVENT201201.dbo.EvAcc
EVENT201202.dbo.EvAcc
EVENT201203.dbo.EvAcc
EVENT201204.dbo.EvAcc
EVENT201205.dbo.EvAcc
...
EVENTYYYYMM.dbo.EvAcc
I also have DBACCES1.dbo.*. I created a query like this :
DECLARE #SQL varchar(511)
DECLARE #SQL_ACC varchar(250)
DECLARE #SQL_UClass varchar(250)
DECLARE #SQL_UClassDef varchar(250)
DECLARE #TABLENAME varchar(250)
SELECT #TABLENAME ='EVENT' + CONVERT(char(4), YEAR(GETDATE() - 1)) + CONVERT(char(2), MONTH(GETDATE() - 1))
SELECT #SQL_ACC = '' + QuoteName(#TABLENAME) + '.dbo.EvAcc ON EvAcc.fpointeur = cards.fpointeur'
SELECT #SQL_UClass = 'dbacces1.dbo.UClass ON UClass.fpointeur = cards.fpointeur AND MClass = 1'
SELECT #SQL_UClassDef = 'dbacces1.dbo.UClassDef ON UClassDef.SClass = UClass.SClass'
SELECT #SQL = 'SELECT cards.FPointeur, Ref, Peri, cout, cin, edate FROM dbacces1.dbo.cards INNER JOIN ' + #SQL_ACC + ' INNER JOIN ' + #SQL_UClass
EXEC(#SQL)
It works but I need to put this in a view. It doesn't work. I have this error (sorry for the french) :
La construction ou l'instruction SQL Déclarer un curseur n'est pas prise en charge.
It say than declare is not allowed in a view.
I tried to create a valued table function and it doen't work because I can't use the function exec with a string in a function. I have this error :
Invalid use of side-effecting or time-dependent operator in 'EXECUTE STRING' within a function.
I also tried to create procedure but I can't use it as a table in my query. I tried to create a function which return the database name only but it doen't work again.
Do you have any solution?
EDIT 1 - Solution
I create a script executed each month. This is my script :
DECLARE #start_date DATETIME
DECLARE #end_date DATETIME
DECLARE #sql VARCHAR(MAX)
DECLARE #dbname VARCHAR(15)
DECLARE #year VARCHAR(4)
DECLARE #month VARCHAR(2)
--Start the SQL request
SET #sql = 'CREATE VIEW dbo.viewEvAcc AS '
SET #start_date = convert(DATETIME, '01/01/2011', 101)
SET #end_date = GETDATE()
--Loop from the start date to now
WHILE #start_date < #end_date
BEGIN
--Find new year and month
SET #year = CONVERT(CHAR(4), YEAR(#start_date))
SET #month = RIGHT('0' + RTRIM(MONTH(#start_date)), 2);
--Create the db name with year and month
SET #dbname = 'EVENT' + #year + #month
--Concat the SQL Request
SET #sql = #sql + 'SELECT * FROM ' + #dbname + '.dbo.EvAcc'
--Update the start date for the month after
SET #start_date = CONVERT(VARCHAR(8),DATEADD(MONTH,1,CONVERT(VARCHAR(8),#start_date,112)),112)
--If the date is not the last date, it add a union
IF #start_date < #end_date
BEGIN
SET #sql = #sql + ' UNION ALL '
END
END
-- drop and create a view with new information
USE dbacces1
IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = 'viewEvAcc')DROP VIEW dbo.viewEvAcc;
EXEC(#sql)
If the view changes periodically (i.e. every day), you could script a job to drop and recreate (alter) the view as needed. It could be part of the job that creates and/or populates that new table.
If the empty tables are created ahead of time, look into creating a partitioned view to union them all. You can then put your query with a join on top of that and add the date constraint to that query's where clause.
Partitioned Views
A view can only contain a static select statement, so as a result if you want to implement dynamic SQL then you will need place this inside of a stored procedure. You could follow these steps:
Create Stored Procedure with your dynamic sql - sp_1
Create stored procedure with your other query - sp_2
Inside this stored procedure, call your sp_1 and insert the results into a temp table
Join this temp table with in your query.
Perhaps you could use synonims : http://msdn.microsoft.com/en-us/library/ms187552(v=sql.100).aspx
You make a static view, which selects data from the synonym object, but before selecting from the view you reassign synonym to the table from the database you need.