insert data from one database to other database dynamically - sql-server

I got one problem while insert data from one db to another
below is my code:
INSERT
INTO myarchivedb.dbo.tblStoreOrderArchive
(
[StoreOrderId]
,[CompanyId]
,[SiteId]
)
SELECT StoreOrderId
,CompanyId
,SiteId
FROM mycurrentdb.dbo.tblStoreOrder
Above code is working fine but myarchivedb and mycurrentdb will change periodically. how to do it dynamically using a variable.

you can try like this
declare #db1 nvarchar(99) = 'myarchivedb.dbo.tblStoreOrderArchive';
declare #db2 nvarchar(99) = 'mycurrentdb.dbo.tblStoreOrder';
-- make sure your query and syntax is correct
PRINT ('INSERT INTO ' + #db1 +
'([StoreOrderId] ,[CompanyId] ,[SiteId] ) SELECT StoreOrderId ,CompanyId ,SiteId FROM ' + #db1)
EXEC ('INSERT INTO ' + #db1 +
'([StoreOrderId] ,[CompanyId] ,[SiteId] ) SELECT StoreOrderId ,CompanyId ,SiteId FROM ' + #db1)

Related

Including list of params in OPENQUERY

I'm trying to get the values from an external Database server executing the following code:
DECLARE #TSQL VARCHAR(8000), #VAR CHAR(2)
DECLARE #Prefixos VARCHAR(MAX);
WITH cte AS
(
SELECT DISTINCT prefixo
FROM ARH.arh.UorPos
)
SELECT #Prefixos = COALESCE(#Prefixos + ', ', '') + prefixo
FROM cte
ORDER BY prefixo
--SELECT #Prefixos --print a list of values separated by comma. eg.: 1, 2, 3
SELECT #TSQL = 'SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,''SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''''' + #Prefixos + ''''''') order by cd_prf_responsavel, codigo'
EXEC (#TSQL)
But I'm getting:
OLE DB provider "MSDASQL" for linked server "DICOI_LINKEDSERVER" returned message "ERRO: syntax error at the end of input;
No query has been executed with that handle".
Msg 7350, Level 16, State 2, Line 1
Cannot get the column information from OLE DB provider "MSDASQL" for linked server "DICOI_LINKEDSERVER".
I've researched the above links to try to resolve it:
How to concatenate text from multiple rows into a single text string in SQL server?
including parameters in OPENQUERY
Join query result to a single line of values separated by comma [duplicate]
Can anyone help me to resolve it ?
Thanks in advance.
Before running your query with EXEC, it's best to just check first how the generated SQL string will look like.
For example by selecting the variable
DECLARE #TSQL VARCHAR(8000), #VAR CHAR(2)
DECLARE #Prefixos VARCHAR(MAX);
WITH cte AS
(
SELECT DISTINCT prefixo
FROM (values ('1'),('2'),('3')) q(prefixo)
)
SELECT #Prefixos = COALESCE(#Prefixos + ', ', '') + prefixo
FROM cte
ORDER BY prefixo
SELECT #TSQL = 'SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,''SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''''' + #Prefixos + ''''''') order by cd_prf_responsavel, codigo'
select #TSQL as TSQL
-- EXEC (#TSQL)
Then you can visually check if there's something odd about it.
Or just try running that sql yourself and see if it fails or not.
From that T-SQL it returns this result :
SELECT * FROM OPENQUERY(DICOI_LINKEDSERVER,'SELECT * FROM ssr.vw_sigas_diage where cd_prf_responsavel in (''1, 2, 3''') order by cd_prf_responsavel, codigo
Notice that there's a bit to many single-quotes in that string.
When using an IN with numbers, the single-quotes are not needed.
And something is missing at the end.
... in ('+ #Prefixos +') order by cd_prf_responsavel, codigo'');';

Paginating a parent in SQL Server on a parent/child query

(SQL Server 2012 - Web Edition)
I have a parent/child (one to many) relationship in a query like so:
SELECT a.a, a.b, b.c
FROM tablea INNER JOIN
tableb ON b.pk = a.fk
I have a huge pagination query that encompasses this using the standard (psuedo-code):
WITH C as (SELECT top(#perpage*#pagenum) rowID = row_number() OVER (somefield)),
SELECT c.* FROM C (query) WHERE DT_RowId > (#pagenum-1)*#perpage
The question I have is in this scenario is it possible to paginate off the parent table (a), instead of the entire query? Can I modify my pagination query (not the sql that pulls the query itself) so that when I ask for 10 rows, it gives me 10 rows from the parent, with 'x' number of children attached?
I know I'm not giving the bigger picture here, but the bigger picture is ugly. If need be, we can go there, but it's out there. Here's a small taste of where we're going with this:
IF UPPER(LEFT(#rSQL, 6)) = 'SELECT'
BEGIN
SET #rSQL = 'SELECT * FROM (' + #rSQL + ')' + ' as rTBL';
SET #rSQL = RIGHT(#rSQL, LEN(#rSQL)-7);
IF (LEN(LTRIM(#search)) > 0)
BEGIN
SET #rPaging =
'IF (#schemaonly=1) SET FMTONLY ON;
SELECT #ttlrows = COUNT(*) FROM (SELECT ' + #rSQL + #rWhere + ') AS TBL;
WITH C as (select top(#perpage*#pagenum) DT_RowId = ROW_NUMBER() OVER (' + #rOrder + '), ';
SET #rPaging = #rPaging + #rSQL + #rWhere + ')
SELECT C.*' + #rcols + ', (#perpage-1) * #pagenum as pagenum, #ttlrows as ct, CEILING(#ttlrows / CAST(#perpage AS FLOAT)) as pages
FROM C '+ #query + ' WHERE DT_RowId > (#pagenum-1) * #perpage ';
END
ELSE
BEGIN
SET #rPaging =
'IF (#schemaonly=1) SET FMTONLY ON;
SELECT #ttlrows = COUNT(*) FROM (' + #oSQL + ') AS SUBQUERY;
WITH C as (select top(#perpage*#pagenum) DT_RowId = ROW_NUMBER() OVER (' + #rOrder + '), ';
SET #rPaging = #rPaging + #rSQL + ')
SELECT C.*' + #rcols + ',(#perpage-1) * #pagenum as pagenum, #ttlrows as ct, CEILING(#ttlrows / CAST(#perpage AS FLOAT)) as pages
FROM C '+ #query + ' WHERE DT_RowId > (#pagenum-1) * #perpage ';
END
PRINT #rPaging;
EXECUTE SP_EXECUTESQL #rPaging, #parms, #ttlrows out, #schemaonly, #perpage, #pagenum, #fksiteID, #filter1, #filter2, #filter3, #filter4, #intfilter1, #intfilter2, #intfilter3, #intfilter4, #datefilter1, #datefilter2, #search;
SET FMTONLY OFF;
END
ELSE
BEGIN
SET #rSQL = LTRIM(REPLACE(UPPER(#rSQL), 'EXEC',''));
EXECUTE SP_EXECUTESQL #rSQL, #parms, #ttlrows out, #schemaonly, #perpage, #pagenum, #fksiteID, #filter1, #filter2, #filter3, #filter4, #intfilter1, #intfilter2, #intfilter3, #intfilter4, #datefilter1, #datefilter2;
END
You could do the pagination in a CTE that only gets the parent rows, and then join the child rows in a subsequent CTE or in the main query.
Due to the dynamic way you are using this, this might have to involve building your pagination query from the same building blocks you use to build #query. Without seeing the code that builds #query I can't be much more specific than that.
You could add
,DENSE_RANK() OVER (ORDER BY table_a.primary_key)
This would indirectly provide the same result as
,ROW_NUMBER() OVER(ORDER BY table_a.primary_key)
but the former would be on the final result set instead going back to table a for the latter code snippet.
But please be aware of the disadvantage: any additional ranking function will force an additional sort operation on the result set! This might significantly influence the query performance. If this is the case in your scenario, I'd recommend to follow Tab Allemans solution and use a cte.

SQL Server build dynamic sql

I have a temp table called #temp, and I need to get all the CDate column from that table, to build a string.
The CDate list in that table is (20171209, 20171210....20171223)
I expected to see
'A.[20171209] as [20171209], A.[20171210] as [20171210],
A.[20171211] as [20171211], A.[20171212] as [20171212],
A.[20171213] as [20171213], A.[20171214] as [20171214],
A.[20171215] as [20171215], A.[20171216] as [20171216],
A.[20171217] as [20171217], A.[20171218] as [20171218],
A.[20171219] as [20171219], A.[20171220] as [20171220],
A.[20171221] as [20171221], A.[20171222] as [20171222],
A.[20171223] as [20171223], '
however the result I got is missing the first date , ie 'A.[20171209] as [20171209]'
Here is my code:
SELECT
#col2 = ISNULL(#col2 + 'A.' + QUOTENAME(CDate) + ' as ' + QUOTENAME(CDate) + ', ' , '')
FROM
(SELECT DISTINCT CDate FROM #temp) AS tmp;
Your current approach will not work in some cases, it is an undocumented feature, always use For Xml path to concatenating the rows into csv.
SET #col2 = stuff((SELECT ', A.' + Quotename(CDate) + ' as '
+ Quotename(CDate)
FROM (SELECT DISTINCT CDate
FROM #temp) a
FOR xml path('')),1,1,'')

How to compare two comma-separated strings, and return TRUE if there is at least 1 match

I have to variables that contain comma-separated strings:
#v1 = 'hello, world, one, two'
#v2 = 'jump, down, yes, one'
I need a function that will return TRUE if there is at least one match. So in the above example, it would return TRUE since the value 'one' is in both strings.
Is this possible in SQL?
Use a split function (many examples here - CLR is going to be your best option in most cases back before SQL Server 2016 - now you should use STRING_SPLIT()).
Once you have a split function, the rest is quite easy. The model would be something like this:
DECLARE #v1 VARCHAR(MAX) = 'hello, world, one, two',
#v2 VARCHAR(MAX) = 'jump, down, yes, one';
SELECT CASE WHEN EXISTS
(
SELECT 1
FROM dbo.Split(#v1) AS a
INNER JOIN dbo.Split(#v2) AS b
ON a.Item = b.Item
)
THEN 1 ELSE 0 END;
You can even reduce this to only call the function once:
SELECT CASE WHEN EXISTS
(
SELECT 1 FROM dbo.Split(#v1)
WHERE ', ' + LTRIM(#v2) + ','
LIKE '%, ' + LTRIM(Item) + ',%'
) THEN 1 ELSE 0 END;
On 2016+:
SELECT CASE WHEN EXISTS
(
SELECT 1 FROM STRING_SPLIT(#v1, ',')
WHERE ', ' + LTRIM(#v2) + ','
LIKE '%, ' + LTRIM([Value]) + ',%'
) THEN 1 ELSE 0 END;
You can use CTEs to split your string into xml nodes, then insert the words into table variables. Joining the table variables will reveal any matches
DECLARE #v1 VARCHAR(200) = 'hello, world, one, two'
DECLARE #v2 VARCHAR(200) = 'jump, down, yes, one'
DECLARE #v1Words TABLE (word VARCHAR(100))
DECLARE #v2Words TABLE (word VARCHAR(100))
;WITH cteSplitV1 AS(
SELECT CAST('<word>' + REPLACE(#v1,', ','</word><word>') + '</word>' AS XML) AS words)
INSERT INTO #v1Words(word)
SELECT word.x.value('.','VARCHAR(100)') AS [word]
FROM cteSplitV1
CROSS APPLY words.nodes('/word') AS word(x)
;WITH cteSplitV2 AS(
SELECT CAST('<word>' + REPLACE(#v2,', ','</word><word>') + '</word>' AS XML) AS words)
INSERT INTO #v2Words(word)
SELECT word.x.value('.','VARCHAR(100)') AS [word]
FROM cteSplitV2
CROSS APPLY words.nodes('/word') AS word(x)
SELECT *
FROM #v1Words v1
JOIN #v2Words v2
ON v1.word = v2.word

Error trying to insert data using trigger T-SQL

Below is a trigger used on one of our SQL tables for any insert/update action. 99/100 times this trigger works just fine however every now and then we receive this error message:
Cannot insert the value NULL into column 'TransactionDate', table
'AgentResourcesU01.dbo.TransactionLog'; column does not allow nulls.
INSERT fails. The statement has been terminated.
As you can see from the Insert statement, the columns in our transaction log table are TransactionDate, Operator, TableName, Action, TableString and UserId. I set the variable #transDate in the opening SELECT statement so as it appears to me, there should be no way a NULL gets in there unless it's bad data coming in.
Any thoughts?
BEGIN
SELECT #symetraNumber = SymetraNumber, #lastChangeOperator = LastChangeOperator, #transDate = LastChangeDate, #entityType = EntityType,
#firstName = FirstName, #lastName = LastName, #suffix = NameSuffix, #corpName = CorporateName, #controlId = ControlId
FROM inserted
IF #firstName IS NULL SET #firstName = 'NULL'
IF #lastName IS NULL SET #lastName = 'NULL'
IF #suffix IS NULL SET #suffix = 'NULL'
IF #corpName IS NULL SET #corpName = 'NULL'
IF #controlId IS NULL SET #controlId = 'NULL'
SET #tableString = 'SymNum:' + #symetraNumber + ' EntType:' + #entityType + ' Fname:' + #firstName + ' Lname:' + #lastname + ' Suff:' + #suffix +
' CorpName:' + #corpName + ' ctrlId:' + #controlId
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
VALUES (#transDate, 'Op', #tableName, #action, #tableString, #lastChangeOperator)
END
To demonstrate Marc's point, you can do this in a set-based way, without all these nasty variables and IF checks:
INSERT dbo.TransactionLog
(
TransactionDate,
Operator,
TableName,
Action,
TableString,
UserId
)
SELECT
LastChangeDate,
'Op',
#TableName,
#action,
'SymNum:' + COALESCE(SymetraNumber, 'NULL')
+ ' EntType:' + COALESCE(EntityType, 'NULL')
+ ' Fname:' + COALESCE(FirstName, 'NULL')
+ ' Lname:' + COALESCE(LastName, 'NULL')
+ ' Suff:' + COALESCE(NameSuffix, 'NULL')
+ ' CorpName:' + COALESCE(CorporateName, 'NULL')
+ ' ctrlId:' + COALESCE(ControlId, 'NULL'),
LastChangeOperator
FROM inserted;
If LastChangeDate in the underlying table is NULLable, either mark it as NOT NULL, fix the problem where NULL is getting inserted, or both. The trigger shouldn't have to know about this constraint but you can work around it by doing something like this (if the value is NULL, set it to right now):
...
UserId
)
SELECT
COALESCE(LastChangeDate, CURRENT_TIMESTAMP),
'Op',
...
[1] I assume that you have an INSERT/UPDATE/DELETE trigger and when somebody try to delete rows from the base table then the inserted table from trigger will have zero rows. Look at this example:
CREATE TABLE MyTableWithTrigger (
MyID INT IDENTITY PRIMARY KEY,
LastUpdateDate DATETIME NOT NULL
);
GO
CREATE TABLE TransactionLog (
TransactionLogID INT IDENTITY PRIMARY KEY,
CreateDate DATETIME NOT NULL DEFAULT GETDATE(),
LastUpdateDate DATETIME NOT NULL,
MyID INT NOT NULL
);
GO
CREATE TRIGGER trIUD_MyTableWithTrigger_Audit
ON MyTableWithTrigger
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE #LastUpdateDate DATETIME, #MyID INT;
SELECT #LastUpdateDate=i.LastUpdateDate, #MyID=i.MyID
FROM inserted i;
INSERT TransactionLog (LastUpdateDate, MyID)
VALUES (#LastUpdateDate, #MyID)
END;
GO
PRINT 'Test 1'
INSERT MyTableWithTrigger (LastUpdateDate)
VALUES ('2011-01-01');
DELETE MyTableWithTrigger;
SELECT * FROM MyTableWithTrigger;
SELECT * FROM TransactionLog;
Output:
Msg 515, Level 16, State 2, Procedure trIUD_MyTableWithTrigger_Audit, Line 10
Cannot insert the value NULL into column 'LastUpdateDate', table 'Test.dbo.TransactionLog'; column does not allow nulls. INSERT fails.
The statement has been terminated.
[2] To correct your trigger (see Marc's comment) please read pages 192 - 199 from Alex Kuznetsov's book (Defensive Database Programming with SQL Server: Amazon, Red Gate - PDF).

Resources