dynamic sql not parsing correctly - sql-server

I am writing a dynamic sql statement that will check if the index exist and drop it. Getting compile error Could somebody tell what the problem is . I double checked the ticks but cant understand
declare #startyear int = 2000
declare #startQuarter int = 1
declare #sql nvarchar(max)
declare #tableName varchar(50)
if #startYear is null
set #startYear = 2000;
set #startQuarter = 1;
while #startYear <= year(getdate())
begin
set #startQuarter = 1;
while #startQuarter < 5
begin
set #tableName = 'FinData' + cast(#startYear as varchar) + '_' + cast(#startQuarter as varchar);
set #sql = 'IF EXISTS(SELECT * FROM sys.indexes WHERE object_id = object_id(' + #tableName + ') AND NAME = ' + '.idx_' + #tableName
drop index' + #tableName + '.idx_' + #tableName
print #sql
set #startQuarter += 1
end
set #startYear += 1;
end

Two issues: this isn't adding anything before the .idx, it's just concatenating the strings together:
') AND NAME = ' + '.idx_'
And then there's a single-quote missing at the end of that line. It looks like your indexes are named after the table's name: tablename.idx_tablename, so try this:
DECLARE #startyear INT = 2000;
DECLARE #startQuarter INT = 1;
DECLARE #sql NVARCHAR(MAX);
DECLARE #tableName VARCHAR(50);
IF #startyear IS NULL
SET #startyear = 2000;
SET #startQuarter = 1;
WHILE #startyear <= YEAR(GETDATE())
BEGIN
SET #startQuarter = 1;
WHILE #startQuarter < 5
BEGIN
SET #tableName = 'FinData' + CAST(#startyear AS VARCHAR) + '_'
+ CAST(#startQuarter AS VARCHAR);
SET #sql = 'IF EXISTS(SELECT * FROM sys.indexes WHERE object_id = object_id('
+ #tableName + ') AND NAME = ' + #tableName + '.idx_' + #tableName + '
drop index' + #tableName + '.idx_' + #tableName;
PRINT #sql;
SET #startQuarter += 1;
END;
SET #startyear += 1;
END;

This does not answer your question, however, it is worth mentioning that if you want to do this without looping, you could create a virtual numbers table to join with.
;WITH
A AS(SELECT 0 AS Q UNION ALL SELECT 0),
B AS(SELECT 0 AS Q FROM A AS A CROSS JOIN A AS B),
C AS(SELECT 0 AS Q FROM B AS A CROSS JOIN B AS B),
D AS(SELECT 0 AS Q FROM C AS A CROSS JOIN C AS B),
E AS(SELECT 0 AS Q FROM D AS A CROSS JOIN D AS B),
F AS(SELECT 0 AS Q FROM E AS A CROSS JOIN E AS B),
Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Number FROM F)
SELECT
Y.Number,Q.Number
FROM
Numbers Y
INNER JOIN Numbers Q ON Q.Number BETWEEN 1 AND 4
WHERE
Y.Number BETWEEN 2000 AND YEAR(GETDATE())
ORDER BY
Y.Number

Related

Merging more than one table into one existing table

This is the table creation and insertion query
If not exists(select * from sysobjects where name='hrs')
Create table hrs(hr int)
declare #cnt int =1
while #cnt <= 12
begin
insert into hrs values(#cnt)
set #cnt=#cnt+1
end
The above code gives the output like
but I just want that
declare #cnt1 int = 1
while #cnt1<=12
begin
EXEC('select he'+#cnt1+' = case when hr = 1 then '+#cnt1+' end from hrs')
set #cnt1=#cnt1+1
end
The above code returns the 12 different table but i just want the all records in one table (without creating any new table).
So, how can i do this?
Please help me.
Thanks.
Here the all column are created dynamically through loop
Here are the full query
declare #s varchar(MAX)=''
declare #j int = 1
while #j<=12
begin
if #j = 12
Set #s = #s+'he'+convert(varchar,#j)+'=MAX(case when hr='+convert(varchar,#j)+' then '+convert(varchar,#j)+' end)'
else
set #s = #s+'he'+convert(varchar,#j)+'=MAX(case when hr='+convert(varchar,#j)+' then '+convert(varchar,#j)+' end),'
set #j=#j+1
end
set #s = 'select '+#s+' from hrs'
exec(#s)
Your query doesn't make a lot of sense, but you can build a list of columns and then exec that:
declare #columns nvarchar(max)
declare #cnt int = 1
while #cnt <= 12
begin
set #columns = isnull(#columns + ', ', '') + 'He' + cast(#cnt as nvarchar) +
' = sum(case when hr = ' + cast(#cnt as nvarchar) + ' then hr end)'
end
declare #sql nvarchar(max) = 'select ' + #columns ' + from hr'
exec (#sql)

The object name contains more than the maximum number of prefixes. The maximum is 2 while running the linked query

I am writing a sql script in sql server that creates dynamic tables based on data.
I was initially getting an error " The object name 'GBIPS-I-DB324D.CoreReferenceStaging.dbo.FinData2000_1' contains more than the maximum number of prefixes. The maximum is 2." while running the original query. GBIPS-I-DB324D is linked server object.
I tried to use execute statement and now getting an error Incorrect syntax near the keyword 'USE'.
Original Query
BEGIN
set nocount on
declare #startYear int, #startQuarter int, #sql nvarchar(max), #tableName varchar(50);
set #startYear = 2000;
set #startQuarter = 1;
while(#startYear < 2018)
begin
set #startQuarter = 1;
while(#startQuarter < 5)
begin
set #tableName = 'FinData' + cast(#startYear as varchar) + '_' + cast(#startQuarter as varchar);
set #sql = '
drop table [GBIPS-I-DB324D].[CoreReferenceStaging].[dbo].[' + #tableName + '];
create table [GBIPS-I-DB324D].[CoreReferenceStaging].[dbo].[' + #tableName + '] ( calendarYear int, calendarQuarter int, companyid bigint not null, dataitemid bigint not null, dataitemvalue numeric(28,6), fiscalyear int, fiscalquarter int, periodenddate datetime, filingdate datetime, latestforfinancialperiodflag bit, latestfilingforinstanceflag bit );
insert into [GBIPS-I-DB324D].[CoreReferenceStaging].[dbo].[' + #tableName + ']
select fp.calendarYear, fp.calendarQuarter, fp.companyid, fd.dataitemid, fd.dataitemvalue, fp.fiscalyear, fp.fiscalquarter, fi.periodenddate, fi.filingdate, fi.latestforfinancialperiodflag, fi.latestfilingforinstanceflag
from [Xpressfeed_dev].[dbo].[ciqFinPeriod] fp
inner join [Xpressfeed_dev].[dbo].[ciqFinInstance] fi on fi.financialPeriodId = fp.financialPeriodId
inner join [Xpressfeed_dev].[dbo].[ciqFinInstanceToCollection] fc on fc.financialInstanceId = fi.financialInstanceId
inner join [Xpressfeed_dev].[dbo].[ciqFinCollection] c on c.financialCollectionId = fc.financialCollectionId
inner join [Xpressfeed_dev].[dbo].[ciqFinCollectionData] fd on fd.financialCollectionId = c.financialCollectionId
where YEAR(fi.periodenddate) = ' + cast(#startYear as varchar) + ' and QUARTER(fi.periodenddate) = ' + cast(#startQuarter as varchar)
EXEC sp_executesql #sql
set #startQuarter += 1
end
set #startYear += 1;
end
end
modified query
BEGIN
set nocount on
declare #startYear int, #startQuarter int, #sql nvarchar(max), #tableName varchar(50);
set #startYear = 2000;
set #startQuarter = 1;
while(#startYear < 2018)
begin
set #startQuarter = 1;
while(#startQuarter < 5)
begin
set #tableName = 'FinData' + cast(#startYear as varchar) + '_' + cast(#startQuarter as varchar);
set #sql = '
EXECUTE (USE CoreReferenceStaging;drop table [dbo].[' + #tableName + ']) AT [GBIPS-I-DB324D]
EXECUTE (USE CoreReferenceStaging;create table [dbo].[' + #tableName + '] ( calendarYear int, calendarQuarter int, companyid bigint not null, dataitemid bigint not null, dataitemvalue numeric(28,6), fiscalyear int, fiscalquarter int, periodenddate datetime, filingdate datetime, latestforfinancialperiodflag bit, latestfilingforinstanceflag bit )) AT [GBIPS-I-DB324D]
insert into [GBIPS-I-DB324D].[CoreReferenceStaging].[dbo].[' + #tableName + ']
select fp.calendarYear, fp.calendarQuarter, fp.companyid, fd.dataitemid, fd.dataitemvalue, fp.fiscalyear, fp.fiscalquarter, fi.periodenddate, fi.filingdate, fi.latestforfinancialperiodflag, fi.latestfilingforinstanceflag
from [Xpressfeed_dev].[dbo].[ciqFinPeriod] fp
inner join [Xpressfeed_dev].[dbo].[ciqFinInstance] fi on fi.financialPeriodId = fp.financialPeriodId
inner join [Xpressfeed_dev].[dbo].[ciqFinInstanceToCollection] fc on fc.financialInstanceId = fi.financialInstanceId
inner join [Xpressfeed_dev].[dbo].[ciqFinCollection] c on c.financialCollectionId = fc.financialCollectionId
inner join [Xpressfeed_dev].[dbo].[ciqFinCollectionData] fd on fd.financialCollectionId = c.financialCollectionId
where YEAR(fi.periodenddate) = ' + cast(#startYear as varchar) + ' and QUARTER(fi.periodenddate) = ' + cast(#startQuarter as varchar)
EXEC sp_executesql #sql
set #startQuarter += 1
end
set #startYear += 1;
end
end
As far as i know, the 'USE' statement cannot be used when working with Linked Servers. This doesn't answer your question about the maximum of 2 but 'Use' is not the way to go. When there is no Linked Server in the game, you can use 'USE', but build the use-statement in the same statement that does the DML operation. You'll have to use Dynamic SQL for that which also have side-effects

CTE having dynamic variable

I have these 2 example of CTE statement, one is hardcoded and the other is dynamic. The hardcoded works but not the dynamic. Can you check what's wrong with my dynamic statement? Thanks
-- THIS WORKS
WITH CTE AS
(
SELECT TOP 1 *
FROM Citi_v823_21Nov2013.dbo.GroupRelation_Audit
WHERE Citi_v823_21Nov2013.dbo.GroupRelation_Audit.ParentEntityIDCounter = #ParentEntityIDCounter
AND Citi_v823_21Nov2013.dbo.GroupRelation_Audit.ChildEntityIDCounter = #ChildEntityIDCounter
AND IsNull(Citi_v823_21Nov2013.dbo.GroupRelation_Audit.AuditDateModified, '1900-01-01') < GETDATE()
ORDER BY GroupRelationCounter DESC
)
UPDATE CTE SET DateEffectiveTo = #DateEffectiveFrom_GroupRelation
--THIS DOESN'T WORK
DECLARE #TargetDB NVARCHAR(Max)
DECLARE #SourceDB NVARCHAR(Max)
DECLARE #DateEffectiveFrom_GroupRelation DATETIME
DECLARE #UpdateRecords_GroupRelation NVARCHAR(Max)
SET #TargetDB = 'Citi_v823_21Nov2013'
SET #SourceDB = 'UATCitiv82320131018'
SET #DateEffectiveFrom_GroupRelation = '2013-09-29'
SET #UpdateRecords_GroupRelation = '
;WITH CTE AS
(
SELECT TOP 1 *
FROM ' + #TargetDB + '.dbo.GroupRelation_Audit
WHERE ' + #TargetDB + '.dbo.GroupRelation_Audit.ParentEntityIDCounter = ' + CONVERT(NVARCHAR(Max), #ParentEntityIDCounter) +'
AND ' + #TargetDB + '.dbo.GroupRelation_Audit.ChildEntityIDCounter = ' + CONVERT(NVARCHAR(Max), #ChildEntityIDCounter) +'
AND IsNull(' + #TargetDB + '.dbo.GroupRelation_Audit.AuditDateModified, ''1900-01-01'') < GETDATE() ''
ORDER BY ' + #TargetDB + '.dbo.GroupRelation_Audit.GroupRelationCounter DESC
)'
UPDATE CTE SET DateEffectiveTo = #DateEffectiveFrom_GroupRelation
EXEC sp_executesql #UpdateRecords_GroupRelation
Move your UPDATE statement inside the SQL statement.
The CTE is locally-scoped, so that statement won't known what CTE is and will simply throw an invalid object error.
Sample code:
declare #sql nvarchar(max)
select *
into ##t
from
(select 3 as b) tmp
select * from ##t;
set #sql = ';WITH a as (select 1 as b) update ##t set b = (select top 1 * from a) '
EXEC sp_executesql #sql
select * from ##t
drop table ##t

Conversion failed when converting date and/or time from character string?

I use pivot table but when I execute I got this error please help me I am stuck on this thanks in advance sorry if any mistake and please also tell me that how to handle string in string in sql server I use " '' '',''-'' " but not sure it is correct or not please help me as soon as posible here are the query
SELECT #SQL = 'SELECT '
WHile #I <= #Months
BEGIN
SET #YearMonth = REPLACE(LTRIM(SUBSTRING(CONVERT(VARCHAR, DateAdd(Month, #I, #StartDate), 13), 3,9)), ' ', '-')
SET #ColumnText = #YearMonth
SET #SQL = #SQL + 'ISNULL([' + #YearMonth + '], 0.00) as ''' + #ColumnText + ''','
SET #I = #I +1
END
Set #I = 0
SET #SQL = #SQL + 'Product,Supplier,PackPrice,QuantityInPack,Code,SupplierID,Description,RebateAmount
FROM
(
SELECT p.NAME AS product,p.Code AS Code,P.Description as Description,oi.PackPrice,oi.QuantityInPack AS Packsize,S.ID AS SupplierID,s.[Name] AS Supplier,
CASE when oi.RebateType=2 then (oi.PackPrice*oi.RebateAmount)/100 ELSE oi.RebateAmount END AS RebateAmount ,o.Total as TotalSale,
REPLACE(LTRIM(SUBSTRING(CONVERT(VARCHAR, O.CreatedDate, 13), 3,9)), '' '',''-'') as tdate
FROM dbo.SCM_Product p WITH (NOLOCK)
INNER JOIN SCM_OrderItem oi WITH (NOLOCK) ON oi.ProductId = p.ID
LEFT OUTER JOIN dbo.SCM_Supplier s WITH(NoLock) ON oi.SupplierID=s.ID
LEFT OUTER JOIN SCM_Order o WITH (NOLOCK) ON o.Id = oi.ProductId AND O.Status <> 5 -- CANCELLED
AND O.Deleted = 0
WHERE ('''+#SupplierID+''' IS NULL OR s.ID IN (SELECT * FROM GetIDsTableFromIDsList(#SupplierID)))
AND ('''+#ProductID+''' IS NULL OR p.ID IN (SELECT * FROM GetIDsTableFromIDsList(#ProductID)) )
AND (o.CreatedDate >= '''+ dbo.GetDatePart(#StartDate) +''' AND o.CreatedDate <= '''+ dbo.GetDatePart(#Enddate) +''')
GROUP BY REPLACE(LTRIM(SUBSTRING(CONVERT(VARCHAR, o.CreatedDate, 13), 3,9)), '' '',''-''),
s.ID,p.Code,p.NAME,s.NAME,P.Description,oi.packPrice,oi.QuantityInPack,oi.RebateAmount,oi.RebateType,oi.PackPrice,o.Total
) SD
PIVOT
( SUM( SD.TotalSale) FOR SD.tdate IN ('
WHile #I <= #Months
BEGIN
SET #YearMonth = REPLACE(LTRIM(SUBSTRING(CONVERT(VARCHAR, DateAdd(Month, #I, #StartDate), 13), 3,9)), ' ', '-')
IF #I = #Months
BEGIN
SET #SQL = #SQL + ' [' + #YearMonth + ']'
END
ELSE
BEGIN
SET #SQL = #SQL + ' [' + #YearMonth + '],'
END
SET #I = #I +1
END
SET #SQL = #SQL + ')) as pvt
ORDER BY Supplier '
--EXEC(#SQL)
PRINT #SQL
The easiest way of doing it would be to use QUOTENAME() function,because you could easily miss quote in a large query.
Example:
DECLARE #name AS CHAR(10) = 'Revolver'
DECLARE #sql as NVARCHAR(300) = 'SELECT *
FROM Music.Album
WHERE Name ='+ QUOTENAME(#name,'''')
PRINT #sql;
or
DECLARE #name AS CHAR(10) = 'Revolver'
DECLARE #sql as NVARCHAR(300) = 'SELECT *
FROM Music.Album
WHERE Name ='''+ #name + ''''
PRINT #sql;

Concat in function

I've an issue when I try to create a function from a working concat select
Here the function
CREATE FUNCTION dbo.afEvrGetConsequencesConcat
(#id_evr int,#type_evr int)
RETURNS varchar(max)
AS
BEGIN
declare #result varchar(max)
set #result= ''
IF #type_evr = 0
BEGIN
SELECT #result = #result + (case when (CEV.ID_CON is null) then CEV.NOM_CEV else CON.NOM_CON end) + ' ; '
from T_CONSEQUENCE_EVRP CEV
left join T_CONSEQUENCE CON on CEV.id_con=CON.id_con
WHERE CEV.id_evr = #id_evr
END
IF #type_evr = 1
BEGIN
SELECT DISTINCT #result = #result + isnull(NOM_PHR,'') + ' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN T_PRODUIT_PHRASE_R PROD_PHR on PROD.ID_PROD=PROD_PHR.ID_PROD
INNER JOIN T_PHRASE_R PHR on PROD_PHR.ID_PHR=PHR.ID_PHR
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PHR.flag_consequence = 1
UNION
SELECT DISTINCT #result = #result + isnull(nom_cons_txt,'') +' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN t_consequence_txt PROD_CONS on PROD.ID_PROD=PROD_CONS.ID_PROD
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PROD.transverse_prod = 1
END
RETURN #result
END
GO
And the message error is 'Msg 444, Niveau 16, État 2, Procédure afEvrGetConsequencesConcat, Ligne 23
Select statements included within a function cannot return data to a client.'
The SELECT above works well outside a function. Each time, I got 1 varchar in #result, that match with the SELECT concat. And this similary function works well too :
CREATE FUNCTION dbo.afEvrGetControleConcat
(#id_evr int,#type_evr int,#type_ctrl int)
RETURNS varchar(8000)
AS
BEGIN
declare #result varchar(8000)
set #result= ''
-- 0 tous
-- 1 date + comm
IF #type_ctrl = 0
BEGIN
SELECT #result = #result + ( CONVERT(VARCHAR(10),date_ctr, 103) + ' - ' + CONVERT(VARCHAR(30),isnull(valeur_mesure,'')) + ' - ' + isnull(unite_mesure,'') + ' - ' + com_ctr ) + ' ;'
FROM t_controle_exposition
WHERE id_evr = #id_evr
END
IF #type_ctrl = 1
BEGIN
SELECT #result = #result + ( CONVERT(VARCHAR(10),date_ctr, 103) + ' - ' + com_ctr ) + ' ;'
FROM t_controle_exposition
WHERE id_evr = #id_evr
END
RETURN #result
END
GO
Then what is the problem ? By logic, I want return a varchar, not a table or any funky data. So I don't unterstand this error message.
Thank for your help.
EDIT: Add a temporary table and insert inside the result of UNION and concat next works well :)
CREATE FUNCTION dbo.afEvrGetConsequencesConcat
(#id_evr int,#type_evr int)
RETURNS varchar(max)
AS
BEGIN
declare #result varchar(max)
set #result= ''
declare #t as table (v varchar(max))
IF #type_evr = 0
BEGIN
SELECT #result = #result + (case when (CEV.ID_CON is null) then CEV.NOM_CEV else CON.NOM_CON end) + ' ; '
from T_CONSEQUENCE_EVRP CEV
left join T_CONSEQUENCE CON on CEV.id_con=CON.id_con
WHERE CEV.id_evr = #id_evr
END
IF #type_evr = 1
BEGIN
insert into #t
SELECT DISTINCT isnull(NOM_PHR,'') + ' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN T_PRODUIT_PHRASE_R PROD_PHR on PROD.ID_PROD=PROD_PHR.ID_PROD
INNER JOIN T_PHRASE_R PHR on PROD_PHR.ID_PHR=PHR.ID_PHR
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PHR.flag_consequence = 1
UNION
SELECT DISTINCT isnull(nom_cons_txt,'') +' ; '
FROM T_EVRP EVR
INNER JOIN T_EVR_CHIM CHIM on EVR.ID_EVR=CHIM.ID_EVR
INNER JOIN T_PRODUIT PROD on CHIM.ID_PROD=PROD.ID_PROD
INNER JOIN t_consequence_txt PROD_CONS on PROD.ID_PROD=PROD_CONS.ID_PROD
WHERE TYPE_EVR=1 AND EVR.id_evr = #id_evr AND PROD.transverse_prod = 1
SELECT #result = #result + v FROM #t
END
RETURN #result
END
GO
I think this is to do with the UNION. Try running:
DECLARE #result varchar(max)
SELECT #result = 'test'
UNION
SELECT #result = 'another'
You will get:
Msg 10734, Level 15, State 1, Line 5
Variable assignment is not allowed in a statement containing a top level UNION, INTERSECT or EXCEPT operator.
If you must do the UNION, you're going to have to return a table, otherwise come up with some other way without the UNION. This could explain why the second function works, as it doesn't have a UNION

Resources