SQL Server trigger locks table - sql

I'm not very versed in writing SQL, but I'm attempting to implement a trigger after INSERT.
The trigger will fire, however, the more complicated this particular SELECT statement gets it seems that it locks the table. If I simplify the statement to only have a couple of argument it runs fine.
If I run the SELECT statement from SSMS, it works, and if I run it from Visual Studio in the VB.net application, it also works. I've tried increasing the command timeout but it still fails. There are only a few rows of data in the table.
Any insight would be greatly appreciated. Please let me know if more detail is required. This is a payroll timeclock table, I'm triggering when a record is inserted and then grabbing the previous days clock out date (so I can compare the previous days payroll hours to the previous days project hours).
I forgot to mention that I'm running the SELECT statement on a view I created that includes two tables from the native application.
SELECT TOP 1
#LastDateClockOut = datEvent
FROM
MyTable.dbo.TimeMTSView
WHERE
datEvent < #Today
AND strUniqueID = #nUser
AND blnEventType = 0
AND lngClassificationID = 0
ORDER BY
datEvent DESC;
Here is the entire trigger:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trgAfterInsert]
ON [dbo].[tblTimes]
AFTER INSERT
AS
DECLARE #trg_lngClassificationID int;
SELECT #trg_lngClassificationID = i.lngClassificationID
FROM inserted i;
IF (#trg_lngClassificationID = 0) --If the date Classification is 0 this means it is NORMAL time as opposed to VACATION or HOLIDAY
DECLARE #trg_lngID int;
DECLARE #trg_lngEmployeeID varchar(20);
DECLARE #trg_blnEventType bit;
DECLARE #blnEventChar nvarchar(1);
DECLARE #trg_datEvent datetime;
DECLARE #nUser varchar(255);
DECLARE #cmd varchar(255);
DECLARE #Today varchar(255);
DECLARE #LastDateClockOut datetime;
DECLARE #strLastClock varchar(255);
SELECT #trg_lngID = i.lngID FROM inserted i;
SELECT #trg_lngEmployeeID = i.lngEmployeeID FROM inserted i;
SELECT #trg_blnEventType = i.blnEventType FROM inserted i;
SELECT #trg_datEvent = i.datEvent FROM inserted i;
SELECT #nUser = strUniqueID
FROM dbo.tblEmployees
WHERE lngID = #trg_lngEmployeeID AND blnDeleted = 0
SELECT #blnEventChar = CONVERT(NVARCHAR, #trg_blnEventType);
SELECT #Today = CONVERT(VARCHAR, GetDate(), 103);
SELECT TOP 1 #LastDateClockOut = datEvent
FROM MyTable.dbo.TimeMTSView
WHERE datEvent < #Today
AND strUniqueID = #nUser
AND blnEventType = 0
AND lngClassificationID = 0
ORDER BY datEvent DESC --This is what fails
SELECT #strLastClock = CONVERT(VARCHAR, #LastDateClockOut, 103);
-- Grab the path to the TimeMTSTrigger.exe written out by the application itself to a log file:
DECLARE #FileContents VARCHAR(MAX)
SELECT #FileContents = BulkColumn
FROM OPENROWSET(BULK'C:\MTSPath\MTSPath.sql', SINGLE_BLOB) x;
SET #cmd = 'Start ' + #FileContents + ' ' + #nUser + ' ' + #blnEventChar + ' ' + #strLastClock
EXEC xp_cmdshell #cmd

I was able to resolve this by not running the SELECT statement on the View I had created in a separate database.
The View had combined two tables from the TIMECLOCKMTS database just to make it easier to grab data. However, the SELECT statement on the View would not run in the SQL Trigger or the exe itself, both would hang and timeout.
By eliminating the View from both the Trigger and EXE and only referencing tables in the Trigger's database this runs perfectly:
USE [TIMECLOCKMTS]
GO
/****** Object: Trigger [dbo].[trgAfterInsert] Script Date: 5/19/2018 2:22:34 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trgAfterInsert] ON [dbo].[tblTimes]
AFTER INSERT
AS
declare #trg_lngClassificationID int;
SELECT #trg_lngClassificationID=i.lngClassificationID from inserted i;
IF (#trg_lngClassificationID = 0) --If the date Classification is 0 this means it is NORMAL time as opposed to VACATION or HOLIDAY
declare #trg_lngID int;
declare #trg_lngEmployeeID varchar(20);
declare #trg_blnEventType bit;
declare #blnEventChar nvarchar(1);
declare #trg_datEvent datetime;
declare #nUser varchar(255);
declare #cmd varchar(255);
declare #Today varchar(255);
declare #LastDateClockOut datetime;
SELECT #trg_lngID=i.lngID from inserted i;
SELECT #trg_lngEmployeeID=i.lngEmployeeID from inserted i;
SELECT #trg_blnEventType=i.blnEventType from inserted i;
SELECT #trg_datEvent=i.datEvent from inserted i;
SELECT #nUser = strUniqueID FROM dbo.tblEmployees WHERE lngID = #trg_lngEmployeeID AND blnDeleted = 0
SELECT #blnEventChar = CONVERT(NVARCHAR, #trg_blnEventType);
--Grab the path to the TimeMTSTrigger.exe written out by the application itself to a log file:
DECLARE #FileContents VARCHAR(MAX)
SELECT #FileContents=BulkColumn
FROM OPENROWSET(BULK'C:\MTSPath\MTSPath.sql',SINGLE_BLOB) x;
SET #cmd = 'Start ' + #FileContents + ' ' + #nUser + ' ' + #blnEventChar + ' ' + #trg_lngEmployeeID
EXEC xp_cmdshell #cmd

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

I have a trigger on my SQL Server table which takes user updates and log them, in case we need to revert, but it has a problem

The problem is, sometimes in a day that no one is changing anything, a random user just enter the page and the trigger saves a change. The problem is, not only it logs a change that never has occurred in that day/moment(Because he/she didn't made a change), but it also gets a random data from INSERTED/DELETED, like we have a log of a change on may 5 2019 that has the date of change set in 2014, which is a long time ago.
My trigger is similar to this one below, just without personal information. We simulated this problem by making changes on a day, then trigger logs it correctly, after that we change the date on our computer, log in and wait a little bit, than it logs something random. Sometimes it takes a lot of time, and enter/exiting pages, but eventually something completely random appears from another date from long ago. Thanks for the help!
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[tablelog]
ON [dbo].[tablechanged]
AFTER UPDATE
AS
BEGIN
declare #OLD_DATA nvarchar(2000);
declare #NEW_DATA nvarchar(2000);
declare #Counter INT;
declare #Occurrences INT;
declare #col varchar(1000);
declare #SELECDELET nvarchar(2000);
declare #SELECINSER nvarchar(2000);
declare #user varchar(50);
declare #cod int;
declare #emp INT;
declare #isReg bit;
set #Occurrences = (SELECT COUNT(COLUMN_NAME) FROM information_schema.columns WHERE table_name = 'tablechanged')
set #Counter = 0;
set #user = (SELECT TOP 1 usuarioUltimaAlteracao FROM INSERTED);
set #emp = (SELECT TOP 1 empCodigo FROM INSERTED);
set #cod = (SELECT TOP 1 cedCodigo FROM INSERTED);
set #isReg = (SELECT TOP 1 alteracaoViaCadastro FROM INSERTED);
SELECT * INTO #Del FROM DELETED
SELECT * INTO #Ins FROM INSERTED
if(#isReg = 1)
begin
while #Counter < #Occurrences
begin
set #Counter = #Counter + 1;
set #col = (select COLUMN_NAME FROM information_schema.columns WHERE table_name = 'tablechanged' and ordinal_position = #Counter);
select #SELECDELET = 'SELECT #OLD_DATA='+#col+' FROM #Del' ;
select #SELECINSER = 'SELECT #NEW_DATA='+#col+' FROM #Ins' ;
exec sp_executesql #SELECDELET, N'#OLD_DATA nvarchar(40) OUTPUT', #OLD_DATA OUTPUT
exec sp_executesql #SELECINSER, N'#NEW_DATA nvarchar(40) OUTPUT', #NEW_DATA OUTPUT
if(#OLD_DATA <> #NEW_DATA)
begin
INSERT INTO TABLELOG (OPE_DATE,OPE_USER,OPE_TABLE,OPE_COD,OPE_EMP,OPE_FIELD,OPE,OLD_DATA,NEW_DATA)
VALUES (getdate(), #user, 'tablechanged', #cod, #emp, #col, 'UPDATE', #OLD_DATA,#NEW_DATA)
end
end
end
END
SQL Server triggers fire for every statement. Not for every row. Your trigger is obviously broken for the case of a multi-row update.
In the case of a multi-row update, the value of #NEW_DATA after running
SELECT #NEW_DATA='+#col+' FROM #Ins' ;
will be the last value in #Ins, and without an ORDER BY, it's undocumented which row it come from.

Sum up values from databases and parametrize it. [SQL Server]

I want to sum up values from several databases. At this moment I have three databases: SPA_PROD, SPB_PROD and SPC_PROD.
My SQL query:
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[TESTSUM]')
AND TYPE IN (N'P',N'PC'))
DROP PROCEDURE [dbo].[TESTSUM]
GO
CREATE PROC TESTSUM
AS
BEGIN
DECLARE #dbName SYSNAME,
#ObjectSUM INT,
#d datetime
SET #d = '20141113'
DECLARE #SQL NVARCHAR(MAX)
DECLARE #DBObjectStats TABLE (
--DBName SYSNAME,
DBObjects INT)
DECLARE curAllDBs CURSOR FOR
SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name like '%PROD'
ORDER BY name
OPEN curAllDBs
FETCH curAllDBs INTO #dbName
WHILE (##FETCH_STATUS = 0) -- db loop
BEGIN
--SQL QUERY
SET #SQL = 'select #dbObjects = sum(doctotal) from ' +
QuoteName(#dbName) + '..Invoice
where DocDate = ''' + cast(#d as varchar(25)) + ''''
PRINT #SQL -- Debugging
EXEC sp_executesql #SQL, N'#dbObjects int output',
#dbObjects = #ObjectSUM output
INSERT #DBObjectStats
SELECT #ObjecSUM
FETCH curAllDBs INTO #dbName
END
CLOSE curAllDBs
DEALLOCATE curAllDBs
-- Return results
SELECT sum(DBObjects) [InvoiceSUM] FROM #DBObjectStats
END
GO
-- Execute stored procedure
EXEC TESTSUM
GO
And this work perfect and giving me right sum from all my DBs: 120 000$ ( 25 000 from SPA_PROD , 95 000 SPC_PROD and 0 (NULL) from SPB_PROD.
What I want to do:
I would like to parametrize, which allows me to choose date and databases. For example I want to choose SPA_PROD and SPB_PROD with date 2014-01-01 in another case I want all databases (SPA + SPB + SPC with another date.
Is this even possible? Any ideas?
I can use everything what gives me SQL Server 2012 and T-SQL. Maybe this technology offers me easiest way to do this.
I am also using SAP Crystal Reports to convert SQL output into a beautiful report.
Sorry for my English and I tried to describe to you my problem as far as I could. If you want any additional information which helps u to help me -> ask me :).
You can create a User-Defined Table Type:
CREATE TYPE DBTable AS TABLE
(
DBName VARCHAR(128)
);
You can use it as an input parameter of your stored procedure. As well as the date parameter.
CREATE PROCEDURE TESTSUM
#Databases DBTable READONLY
,#Date DATETIME
AS
BEGIN
...
...
...
You call it like this:
DECLARE #T AS DBTable;
DECLARE #D AS DATETIME = GETDATE();
INSERT INTO #T VALUES ('DB1', 'DB2', 'DB3')
EXEC TESTSUM #T, #D
maybe instead of
SELECT name
FROM MASTER.dbo.sysdatabases
use
SELECT name
FROM #temptable
and insert into #temptable specific db you want
Using your example I modified it to accept a string of database names (generated through you crystal reports select action). Then passing this string with the date in question to first validate the database exist and if online add the required union clause to the generated SQL code.
CREATE PROCEDURE TESTSUM
#DbNameS NVARCHAR(max)
,#Date DATETIME
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX) = ''
/* ADD EXTRA ',' RO STRING ARRAY OF DATABASES */
SET #DbNameS = #DbNameS + ',';
DECLARE #L INT = LEN(#DbNameS);
DECLARE #D INT = 0;
DECLARE #LD INT = 1;
DECLARE #DBF VARCHAR(50);
DECLARE #ACTIVE INT = 0;
/* START SQL QUERY */
SET #SQL = 'SELECT SUM([InvoiceSUM]) AS [InvoiceSUM] FROM ( SELECT '''' AS DB, 0.00 AS [InvoiceSUM]' + CHAR(13)
/* LOOP THROUGH EACH DBF NAME PASSED CHECKING IF VALID AND ONLINE */
WHILE #D < #L
BEGIN
SET #D = CHARINDEX(',', #DbNameS,#LD);
IF #LD != #D
BEGIN
SET #DBF = SUBSTRING(#DbNameS,#LD,#D-#LD)
/* VALIDATE DBF IS VALID AND ACTIVE */
SELECT #ACTIVE = COUNT(*) FROM SYS.databases WHERE name = #DBF AND [state] = 0
IF #ACTIVE = 1
BEGIN
/*
BEGIN CODE TO UNION THE SUM RESULTS FOR EACH ACTIVE AND VALID DBF
TO MAKE IT WORK WITH SOME EXISTING DBF's ON MY SYSTEM I CHANGED THE SUMMARY CODE FOR TESTING
*/
SET #SQL = #SQL + 'UNION SELECT '''+ #DBF +''' AS DB, ISNULL(SUM( CAST(DVE AS DECIMAL(18,10)) ),0) AS [InvoiceSUM] FROM '+ #DBF + '.DBO.SO_MSTR WHERE CAST(RecordCreated AS DATE) = '''+ CAST(#Date AS VARCHAR(20)) + '''' + CHAR(13)
END;
END;
SET #LD = #D + 1;
END;
/* CLOSE OUT UNION SUMMARY QUERY */
SET #SQL = #SQL + ') AS DATA'
/* OUTPUT RESULTS */
EXEC SP_EXECUTESQL #SQL
END;
Crystal reports would effective be generating this code: EXEC TESTSUM 'SPA_PROD,SPB_PROD,SPC_PROD','12/09/2014'

SQL Select maxDate in SP

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

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.