Building dynamic self join statements in SQL - sql

Declare #alias as varchar(10)
set #alias = 'fk2'
insert into #Queries(Query, ExecuteOrder)
select top 1 'delete ' + fk1.TableFrom + ' from ' + fk1.TableFrom
+ ' join ' + #alias.TableFrom + ' on ' + fk1.TableFrom+'.'+fk1.FK_Column + ' = ' + fk2.TableFrom + '.ID'
+ ' join ' + fk3.TableFrom + ' on ' + fk2.TableFrom+'.'+fk2.FK_Column + ' = ' + fk3.TableFrom + '.ID'
+ ' join ' + fk4.TableFrom + ' on ' + fk3.TableFrom+'.'+fk3.FK_Column + ' = ' + fk4.TableFrom + '.ID'
+ ' Where ' + fk4.TableFrom + '.' + fk4.FK_Column + ' = ' + #value
,#i
from #FK fk1
join #fk As #alias on #alias.TableFrom = fk1.TableTo
join #fk fk3 on fk3.TableFrom = fk2.TableTo
join #fk fk4 on fk4.TableFrom = fk3.TableTo
I am joining a table to itself to build a resulting query to then be executed from the temp table being inserted into. I am currently specifying the amount of joins but would like to build them dynamically based on another integer value being passed in. The amount of joins will correlate with this integer value. The only problem is I need a unique Alias for each join to then be used above to build the resulting query. Is it possible to use a dynamic Alias as to eliminate the need to hardcode the Alias for each join?

Related

STRING_AGG Issue

I was working with SQL Server 2017 and I used the following query,
select
'select s.' + string_agg (c.source_column + ', t.' + c.target_column, ', ') +
' from ' + t.source_table + ' s' +
' join ' + t.target_table + ' t' +
' on ' + string_agg('t.' + c.target_column + ' = s.' + c.source_column, ' and ') +
';' as query
from configuration_tables t
join configuration_columns c on c.id_configuration_tables = t.id_configuration_tables
group by t.source_table, t.target_table
order by t.source_table, t.target_table;
The query is used to get the list of columns in a string for each table name.
I have to move to 2016 due to some issues, I modified the query as below,
select
distinct 'select ' + STUFF((select ',' + 's.[' + c1.source_column + '],t.[' + c1.target_column + ']'
from recon_configuration_columns c1 where c1.id_recon_configuration_table = c.id_recon_configuration_table FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
+ ' from ' + t.source_table + ' s' +
' join ' + t.target_table + ' t' +
' on ' + STUFF((select ' and ' + 's.[' + c1.source_column + '] = t.[' + c1.target_column + '] ' from recon_configuration_columns c1
where c1.id_recon_configuration_table = c.id_recon_configuration_table FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,5,'')
from
recon_configuration_tables t
join recon_configuration_columns c on c.id_recon_configuration_table = t.id_recon_configuration_table
I would like to know whether the query I changed is a standard one, also it wont create any problems in long run and always both queries should return the same results.
Thanks for your support

Cannot resolve collation conflict for column 2 in SELECT statement

The following SQL statement is giving me a "Cannot resolve collation conflict for column 2 in SELECT statement." error.
I can tell the culprit is RTRIM(TABLE_ONE.AUT_NAME) because the statement works if I remove it. However, if I use COLLATE before it I get a syntax error. How can I resolve this issue? thanks
SELECT NRS, RTRIM(STR_DES) + ', ' + RTRIM(TABLE_TWO.TO_NA)
AS FT_NAME, KEYWORDS = CAST(NRS AS VARCHAR(15)) + ' ' + RTRIM(STR_DES) + '' +
RTrim(TABLE_THREE.LC_NAME) + ' ' + RTRIM(TABLE_TWO.TO_NA) + '' +
RTRIM(TABLE_ONE.AUT_NAME)
From NSG_STR INNER Join TABLE_TWO On TABLE_TWO.TN_UID = NSG_STR.TN_UID INNER Join
TABLE_THREE ON TABLE_THREE.LCT_UID = NSG_STR.LCT_UID INNER JOIN TABLE_ONE ON TABLE_ONE.AUT_UID = NSG_STR.AUT_UID
WHERE CAST(NRS As VARCHAR(15)) + ' ' + RTRIM(STR_DES) + ' ' + RTRIM(TABLE_THREE.LC_NAME) + ' ' + RTRIM(TABLE_TWO.TO_NA) + '' +
RTrim(TABLE_ONE.AUT_NAME) COLLATE DATABASE_DEFAULT LIKE '%3%'
Run this before your code:
declare #db_collation nvarchar(100) = (select cast( databasepropertyex(db_name(),'collation') as nvarchar) )
declare #altertablequery nvarchar(500)
set #altertablequery = '
alter table NSG_AUTHORITY alter column AUTHORITY_NAME nvarchar (max) collate '+#db_collation+';'
exec (#altertablequery)
A better answer is to simply add "COLLATE DATABASE_DEFAULT" to your query, which requires no schema modifications at all.
SELECT USRN, RTRIM(STREET_DESCRIPTOR) + ', ' + RTRIM(NSG_TOWN.TOWN_NAME)
AS FEATURE_NAME, KEYWORDS = CAST(USRN AS VARCHAR(15)) + ' ' + RTRIM(STREET_DESCRIPTOR) + '' +
RTrim(NSG_LOCALITY.LOCALITY_NAME) + ' ' + RTRIM(NSG_TOWN.TOWN_NAME) + '' +
RTRIM(NSG_AUTHORITY.AUTHORITY_NAME) COLLATE DATABASE_DEFAULT
From NSG_STREET INNER Join NSG_TOWN On NSG_TOWN.TOWN_UID = NSG_STREET.TOWN_UID INNER Join
NSG_LOCALITY ON NSG_LOCALITY.LOCALITY_UID = NSG_STREET.LOCALITY_UID INNER JOIN NSG_AUTHORITY ON NSG_AUTHORITY.AUTHORITY_UID = NSG_STREET.AUTHORITY_UID
WHERE CAST(USRN As VARCHAR(15)) + ' ' + RTRIM(STREET_DESCRIPTOR) + ' ' + RTRIM(NSG_LOCALITY.LOCALITY_NAME) + ' ' + RTRIM(NSG_TOWN.TOWN_NAME) + '' +
RTrim(NSG_AUTHORITY.AUTHORITY_NAME) COLLATE DATABASE_DEFAULT LIKE '%3%' COLLATE DATABASE_DEFAULT
You simply use it everywhere it's referenced, and with everything you compare against (to be safe).

when using "SELECT varname = something + something etc. I cannot then do "WHERE varname = ..."

I have:
SELECT KEYWORDS = CAST(USRN AS VARCHAR(15)) + ' ' +
RTRIM(SD) + ' ' + RTRIM(NL.LOCALITY_NAME) + ' ' +
RTRIM(NT.TOWN_NAME) + ' ' + RTRIM(NA.AUTHORITY_NAME)
That gives me what looks like a column, but is not:
I want to have it so my code only selects the rows from KEYWORDS that match whatever the user is typing. Normally, if KEYWORDS was a column, I would write:
SELECT .... WHERE KEYWORDS = '%whateverTheUserIsTyping%'
but I cannot because keywords is not a real column and it is telling me that it does not exist.
How do I get around this? thanks
The column alias KEYWORDS isn't visible to the SQL Engine at the time that the WHERE clause is evaluated. You can just repeat your CAST statment, though.
SELECT
KEYWORDS = CAST(USRN AS VARCHAR(15)) + ' ' +
RTRIM(STREET_DESCRIPTOR) + ' ' + RTRIM(NSG_LOCALITY.LOCALITY_NAME) + ' ' +
RTRIM(NSG_TOWN.TOWN_NAME) + ' ' + RTRIM(NSG_AUTHORITY.AUTHORITY_NAME)
FROM yourTable
WHERE
CAST(USRN AS VARCHAR(15)) + ' ' +
RTRIM(STREET_DESCRIPTOR) + ' ' + RTRIM(NSG_LOCALITY.LOCALITY_NAME) + ' ' +
RTRIM(NSG_TOWN.TOWN_NAME) + ' ' + RTRIM(NSG_AUTHORITY.AUTHORITY_NAME)
LIKE '%whateverTheUserIsTyping%'
You can use derived table with an alias (here Q) and get the result from that by filtering in WHERE clause:
SELECT Q.KEYWORDS FROM (
SELECT KEYWORDS = CAST(USRN AS VARCHAR(15)) + ' ' +
RTRIM(STREET_DESCRIPTOR) + ' ' + RTRIM(NSG_LOCALITY.LOCALITY_NAME) + ' ' +
RTRIM(NSG_TOWN.TOWN_NAME) + ' ' + RTRIM(NSG_AUTHORITY.AUTHORITY_NAME)
) AS Q
WHERE Q.KEYWORDS LIKE '%whateverTheUserIsTyping%'
Because you can't use the column alias in the WHERE clause as you mentioned. Also instead of the KEYWORDS = '%whateverTheUserIsTyping%', you can use LIKE operator.

Dynamic WHERE clause in SQL Server 2008 R2

I have a table which I'm querying using a dynamic conditional WHERE clause. I'm looking a best approach to get simple WHERE condition when all columns are null or when some columns has some value.
I tried something like this:
SET #CONDITIONS = CASE
WHEN #VEHICLE_TYPE_NAME IS NULL
THEN ' ISNULL(A.VEHICLE_TYPE_NAME,'''') = ISNULL(A.VEHICLE_TYPE_NAME,'''') '
ELSE ' A.VEHICLE_TYPE_NAME = ''' + #VEHICLE_TYPE_NAME + ''''
END + ' ' + CASE
WHEN CAST(#PRODUCT_ID AS VARCHAR(MAX)) IS NULL
THEN ' AND ISNULL(A.PRODUCT_ID, ''-1'') = ISNULL(A.PRODUCT_ID, ''-1'') '
ELSE ' AND A.PRODUCT_ID = ''' + CAST(#PRODUCT_ID AS VARCHAR(MAX)) + ''''
END + ' ' + CASE
WHEN CAST(#CAPABILITY_ID AS VARCHAR(MAX)) IS NULL
THEN ' AND ISNULL(A.CAPABILITY_ID,''-1'') = ISNULL(A.CAPABILITY_ID,''-1'') '
ELSE ' AND A.CAPABILITY_ID = ''' + CAST(#CAPABILITY_ID AS VARCHAR(MAX)) + ''''
END + ' ' + CASE
WHEN #SPONSOR_FIRM_ID IS NULL
THEN ' AND ISNULL(A.SPONSOR_FIRM_ID,'''') = ISNULL(A.SPONSOR_FIRM_ID,'''') '
ELSE ' AND A.SPONSOR_FIRM_ID = ''' + #SPONSOR_FIRM_ID + ''''
END + ' ' + CASE
WHEN #CLIENT_FIRM_ID IS NULL
THEN ' AND ISNULL(A.CLIENT_FIRM_ID,'''') = ISNULL(A.CLIENT_FIRM_ID,'''') '
ELSE ' AND A.CLIENT_FIRM_ID = ''' + #CLIENT_FIRM_ID + ''''
END + ' ' + CASE
WHEN CAST(#DIST_PLATFORM_ID AS VARCHAR(MAX)) IS NULL
THEN ' AND ISNULL(A.DIST_PLATFORM_ID,''-1'') = ISNULL(A.DIST_PLATFORM_ID,''-1'') '
ELSE ' AND A.DIST_PLATFORM_ID = ''' + CAST(#DIST_PLATFORM_ID AS VARCHAR(MAX)) + ''''
END + ' ' + CASE
WHEN #RR_INTERNAL_NUMBER IS NULL
THEN 'AND ISNULL(A.RR_INTERNAL_NUMBER,'''') = ISNULL(A.RR_INTERNAL_NUMBER,'''') '
ELSE ' AND A.RR_INTERNAL_NUMBER = ''' + #RR_INTERNAL_NUMBER + ''''
END
You don't need the part where your parameter is null. You can simply build up a dynamic SQL for each part
IF #PRODUCT_ID IS NOT NULL
#CONDITIONS = #CONDITIONS + ' AND A.PRODUCT_ID = ''' + CAST(#PRODUCT_ID AS VARCHAR(MAX)) + ''''
Why do you need dynamic SQL?
WHERE (#VEHICLE_TYPE_NAME IS NULL OR A.VEHICLE_TYPE_NAME = #VEHICLE_TYPE_NAME)
AND (#PRODUCT_ID IS NULL OR A.PRODUCT_ID = #PRODUCT_ID)
...

space in a select statement in dynamic query

I have a dynamic query like this :
SET #str_Query = 'SELECT SIM.Item_ID,
SIM.Item_Description,
SU.Short_Description AS Unit,
SIM.Std_Lead_Time,'+
'' ''+' AS Last_Purchase_Rate
FROM FKMS_Item_Master AS SIM
INNER JOIN FKMS_STP_Units SU
ON SIM.Item_Purchase_Unit=SU.Unit_Id' +
' WHERE ' + #str_Condition +
' AND SIM.Location_Id =' + CAST(#aint_Location_Id AS VARCHAR(10)) +
' AND SIM.Item_Deleted =0
AND SIM.Approved_On IS NOT NULL'
+' ORDER BY SIM.Item_Description'
I want to retrieve space as Last_Purchase_Rate
It is showing syntax error in the portion of '' ''+' AS Last_Purchase_Rate
when I execute this query.
If I print this dynamic query, query seems correct. It shows as AS Last_Purchase_Rate with space before AS. Please help.
I would write
...SIM.Std_Lead_Time, '' '' AS Last_Purchase_Rate...
instead of
...SIM.Std_Lead_Time,'+'' ''+' AS Last_Purchase_Rate...
Why not use NULL instead of space and then handle the result in your app?
I.e.,
SET #str_Query = 'SELECT SIM.Item_ID,
SIM.Item_Description,
SU.Short_Description AS Unit,
SIM.Std_Lead_Time,
NULL AS Last_Purchase_Rate, -- and so on.
You could also use CHAR(32):
SET #str_Query = 'SELECT SIM.Item_ID,
SIM.Item_Description,
SU.Short_Description AS Unit,
SIM.Std_Lead_Time,
CHAR(32) AS Last_Purchase_Rate, -- and so on.
You did not escape all quotes.
A working version of your statement would be
SET #str_Query = 'SELECT SIM.Item_ID,
SIM.Item_Description,
SU.Short_Description AS Unit,
SIM.Std_Lead_Time,'
+ ''' '''
+ ' AS Last_Purchase_Rate
FROM FKMS_Item_Master AS SIM
INNER JOIN FKMS_STP_Units SU
ON SIM.Item_Purchase_Unit=SU.Unit_Id' +
' WHERE ' + #str_Condition +
' AND SIM.Location_Id =' + CAST(#aint_Location_Id AS VARCHAR(10)) +
' AND SIM.Item_Deleted =0
AND SIM.Approved_On IS NOT NULL'
+' ORDER BY SIM.Item_Description'
but I find that with a little reformatting, the error is easier to spot
SET #str_Query =
'SELECT SIM.Item_ID '
+ ', SIM.Item_Description '
+ ', SU.Short_Description AS Unit '
+ ', SIM.Std_Lead_Time '
+ ', '' ''' + ' AS Last_Purchase_Rate '
+ 'FROM FKMS_Item_Master AS SIM '
+ ' INNER JOIN FKMS_STP_Units SU '
+ ' ON SIM.Item_Purchase_Unit=SU.Unit_Id '
+ ' WHERE ' + #str_Condition
+ ' AND SIM.Location_Id = ' + CAST(#aint_Location_Id AS VARCHAR(10))
+ ' AND SIM.Item_Deleted =0 '
+ ' AND SIM.Approved_On IS NOT NULL '
+ ' ORDER BY SIM.Item_Description '
Try using tsql function SPACE(1)