How to do foreach select in single SQL query - sql

I have a problem, i try to do a foreach to select multi row and do a select in a each one.
This is my table :
| TRANSLATION_ID | TABLE_NAME | COLUMN_NAME | ID_COLUMN | CODELANGUE_COLUMN |
|---------------- |------------------------- |------------- |----------- |------------------- |
| 1 | CHAMPS_LANGUE | VALUE1 | ZZZ | CODELANGUE |
| 2 | DELAIS_LIBELLES | VALUE2 | YYY | CODELANGUE |
| 3 | MODELES_ENQUETES_LIGNES | VALUE3 | XXX | CODELANGUE |
| ... | ... | ... | ... | |
And I would like to do multiple SELECT on every TABLE like CHAMPS_LANGUE , DELAIS_LIBELLES etc..
FOREACH TABLE_NAME
SELECT COLUM_NAME, ID_COLUM FROM TABLE_NAME WHERE CODELANGUE = 1
Let me know if a not very explicit. :)

Modified an answer by #legendofawesomeness found here to make it more relevant for your situation
--Cursor for iterating
DECLARE #tableCursor CURSOR
DECLARE #TABLE_NAME NVARCHAR(255)
DECLARE #COLUM_NAME NVARCHAR(255)
DECLARE #ID_COLUM NVARCHAR(255)
DECLARE #CODELANGUE_COLUMN NVARCHAR(255)
SET #tableCursor = CURSOR FOR SELECT TABLE_NAME, COLUM_NAME, ID_COLUMN, CODELANGUE_COLUMN FROM [tableData] -- Substitute with the name of your table as given in your question (which you didn't specify)
OPEN #tableCursor
FETCH NEXT FROM #tableCursor INTO #TABLE_NAME, #COLUM_NAME, #ID_COLUMN, #CODELANGUE_COLUMN
WHILE (##fetch_status = 0)
BEGIN
--dynamic sql
DECLARE #sql NVARCHAR(max)
--Your logic here...
SET #sql = 'SELECT ' + #COLUM_NAME + ', ' + #ID_COLUM + ' FROM ' + #TABLE_NAME + ' WHERE ' + #CODELANGUE_COLUMN + ' = 1'
EXEC dbo.sp_executesql #sql
FETCH NEXT FROM #tableCursor INTO #TABLE_NAME, #COLUM_NAME, #ID_COLUMN, #CODELANGUE_COLUMN
END
CLOSE #tableCursor
DEALLOCATE #tableCursor

Related

SQL combine three rows into one column

Is there any way to solve this? I am practicing SQL and I don't know how to do this.
Image table
----------------------------
| prdctCode | imgPath |
| P0003 | P0003-1.jpg |
| P0003 | P0003-2.jpg |
| P0003 | P0003-3.jpg |
| P0004 | P0004-1.jpg |
| P0004 | P0004-2.jpg |
| P0004 | P0004-3.jpg |
----------------------------
Product table
-------------------------
| prdctCode | prdctName |
| P0003 | Hand Bag |
| P0004 | Pencil |
-------------------------
What I get
---------------------------------------
| prdctCode | prdctName | imgPath |
| P0003 | Hand Bag | P0003-1.jpg |
| P0003 | Hand Bag | P0003-2.jpg |
| P0003 | Hand Bag | P0003-3.jpg |
| P0004 | Pencil | P0004-1.jpg |
| P0004 | Pencil | P0004-2.jpg |
| P0004 | Pencil | P0004-3.jpg |
---------------------------------------
Expected output
--------------------------------------------------------------------
| prdctCode | prdctName | imgPath1 | imgPath2 | imgPath3 |
| P0003 | Hand Bag | P0003-1.jpg | P0003-2.jpg | P0003-3.jpg |
| P0004 | Pencil | P0004-1.jpg | P0004-2.jpg | P0004-3.jpg |
--------------------------------------------------------------------
This is my code
select prdTbl.prdctCode, prdTbl.prdctName, imgTbl.imgPath
from [product_tbl]prdTbl left join [image_tbl]imgTbl
on prdTbl.prdctCode = imgTbl.prdctCode
I'm not sure if this is possible.
If you know for sure that for a product will always be maximum 4 images and that the image is always ending with .jpg, maybe this select can help:
select prdTbl.prdctCode, prdTbl.prdctName, imgTbl2.imgPath as Path1, imgTbl2.imgPath as Path2, imgTbl3.imgPath as Path3, imgTbl4.imgPath as Path4
from [product_tbl]prdTbl
left join [image_tbl]imgTbl1 on prdTbl.prdctCode = imgTbl1.prdctCode and imgTbl1.imgPath like '%-1.jpg'
left join [image_tbl]imgTbl2 on prdTbl.prdctCode = imgTbl2.prdctCode and imgTb12.imgPath like '%-2.jpg'
left join [image_tbl]imgTbl3 on prdTbl.prdctCode = imgTbl3.prdctCode and imgTbl3.imgPath like '%-3.jpg'
left join [image_tbl]imgTbl4 on prdTbl.prdctCode = imgTbl4.prdctCode and imgTbl4.imgPath like '%-4.jpg'
Please consider looking at that script :
CREATE TABLE #TempAppointmentTable (
UniqueID VARCHAR(MAX),
VAL nvarchar(500)
);
INSERT INTO #TempAppointmentTable
([UniqueID], [VAL])
VALUES
('P0003', 'P0003-1.jpg'),
('P0003', 'P0003-2.jpg'),
('P0003', 'P0003-3.jpg'),
('P0004', 'P0004-1.jpg'),
('P0004', 'P0004-2.jpg')
;
DECLARE #list_id TABLE (idx INT IDENTITY, id VARCHAR(MAX))
DECLARE #nb_rows INT
DECLARE #nb_cols INT
DECLARE #i INT = 0
DECLARE #j INT = 0
DECLARE #cur_id VARCHAR(MAX)
DECLARE #cur_nb_rows INT
DECLARE #sql VARCHAR(MAX)
INSERT INTO #list_id(id) SELECT [UniqueID] FROM #TempAppointmentTable GROUP BY [UniqueID] ORDER BY COUNT(*) DESC;
SELECT #nb_rows = COUNT(*) FROM #list_id;
SELECT #nb_cols = MAX(val) FROM (SELECT COUNT(*) FROM #TempAppointmentTable GROUP BY [UniqueID])t(val);
SET #sql = '
WITH TMP ([Row], [UniqueID], [VAL]) AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY [UniqueID] ORDER BY UniqueID), [UniqueID], [VAL] from #TempAppointmentTable
)'
WHILE #i < #nb_rows
BEGIN
SELECT #cur_id = id FROM #list_id WHERE idx = #i+1
SELECT #cur_nb_rows = COUNT(*) FROM #TempAppointmentTable WHERE [UniqueID] = #cur_id
IF #i != 0
SET #sql = #sql + '
UNION'
SET #sql = #sql + '
SELECT TMP' + CONVERT(VARCHAR,#i) + '0.[UniqueID], TMP' + CONVERT(VARCHAR,#i) + '0.[VAL]'
WHILE #j+1 < #nb_cols
BEGIN
SET #j = #j + 1
IF #j < #cur_nb_rows
SET #sql = #sql + ', TMP'+ CONVERT(VARCHAR,#i) + CONVERT(VARCHAR,#j) + '.[VAL] AS [VAL' + CONVERT(VARCHAR,#j) + ']'
ELSE
SET #sql = #sql + ', NULL'
END
SET #j = 0
SET #sql = #sql + '
FROM TMP AS TMP' + CONVERT(VARCHAR,#i) + '0'
WHILE #j+1 < #nb_cols
BEGIN
SET #j = #j + 1
IF #j < #cur_nb_rows
SET #sql = #sql + '
INNER JOIN TMP AS TMP' + CONVERT(VARCHAR,#i) + CONVERT(VARCHAR,#j) + ' ON TMP' + CONVERT(VARCHAR,#i) + CONVERT(VARCHAR,#j) + '.Row = ' + CONVERT(VARCHAR,#j+1) +' AND TMP' + CONVERT(VARCHAR,#i) + CONVERT(VARCHAR,#j) + '.UniqueID = ''' + CONVERT(VARCHAR,#cur_id) + ''''
END
SET #sql = #sql + '
WHERE TMP' + CONVERT(VARCHAR,#i) + '0.Row = 1 AND TMP' + CONVERT(VARCHAR,#i) + '0.UniqueID = ''' + CONVERT(VARCHAR,#cur_id) + ''''
SET #j = 0
SET #i = #i + 1
END
PRINT(#sql)
EXEC(#sql)
Drop table #TempAppointmentTable
The output is
UniqueID
VAL
VAL1
VAL2
P0003
P0003-1.jpg
P0003-2.jpg
P0003-3.jpg
P0004
P0004-1.jpg
P0004-2.jpg
NULL
As you can see it considers the number of elements, so the day you'll have 100 rows for a product (p0003 or any other) it will have 101 columns :D
You can modify that script for your neeeds
I hope it can feets your needs
For any other question I'll be right there

Dynamic Statement to Get Top "n" for Each Individual Column from Ms SQL Table

Help me with this Dynamic statement perform faster, the statement will fetch top n values for each column from a table.
The table will have an "n" number of columns but will have a primary key. NULLs couldn't have been avoided as any other value is considered as VALID and should go to the database.
Table
+-------+------+------+------+
| Depth | RPMA | ROP | WOB |
+-------+------+------+------+
| 6111 | 72 | 14.6 | 0 |
| 6110 | 72 | 14.1 | 1 |
| 6109 | 66 | 15.2 | NULL |
| 6108 | 68 | 14 | NULL |
| 6107 | 69 | 14 | NULL |
| 6106 | 61 | 14.8 | NULL |
| 6105 | 70 | NULL | NULL |
| 6104 | 64 | NULL | NULL |
| 6103 | 59 | NULL | NULL |
| 6102 | 49 | NULL | NULL |
+-------+------+------+------+
Result set,
+-------+------+------+------+
| Depth | RPMA | ROP | WOB |
+-------+------+------+------+
| 6111 | 72 | NULL | 0 |
| 6110 | 72 | NULL | 1 |
| 6109 | NULL | 15.2 | NULL |
| 6106 | NULL | 14.8 | NULL |
+-------+------+------+------+
Dynamic SQL used to get current result set,
DECLARE #Columns VARCHAR(MAX); -- Param1
DECLARE #IdxColumn VARCHAR(250); --Param2
DECLARE #Limit VARCHAR(11); --Param3
DECLARE #SQL NVARCHAR(MAX)=''; --Param4
DECLARE #query NVARCHAR(MAX) = ' SELECT TOP (' + #pLimit + ') ' + #IdxColumn + ', ' + #Columns + ' FROM [Table] WHERE '
SET #SQL = #query + REPLACE(#Columns,',', ' IS NOT NULL ORDER BY '+ #IdxColumn + ' ASC ' + N' UNION' + #query) + ' IS NOT NULL ORDER BY ' + #IdxColumn
SET #SQL = 'SELECT * FROM ('+#SQL+') T ORDER BY ' + #IdxColumn + ' ASC'
EXEC (#SQL)
The following query should work for the sample data:
WITH cte AS (
SELECT *
, DENSE_RANK() OVER (ORDER BY RPMA DESC) AS RPMA_RANK
, DENSE_RANK() OVER (ORDER BY ROP DESC) AS ROP_RANK
, DENSE_RANK() OVER (ORDER BY WOB DESC) AS WOB_RANK
FROM t
)
SELECT Depth
, CASE WHEN RPMA_RANK <= 2 THEN RPMA END
, CASE WHEN ROP_RANK <= 2 THEN ROP END
, CASE WHEN WOB_RANK <= 2 THEN WOB END
FROM cte
WHERE RPMA_RANK <= 2
OR ROP_RANK <= 2
OR WOB_RANK <= 2
Note that it returns three rows for RPMA column (there are two 72 and one 70). For n number of columns you need to use dynamic SQL.
This doesn't answer the question, but does fix the terrifying security flaws in the above.
There are multiple problems with the above, so please note that this is a significant but needed change to the SQL you have. Right now you are injecting unsantised parameters into your code, and also using datatypes that are vastly too large. #Columns is varchar(MAX), meaning that someone has 2GB worth of characters to inject into your system. #IdxColumn is a varchar(250) and references a single column; an object can at most be 128 characters long so there's no need for the other 122 characters. Also #Limit is a varchar, despite being an int and should be a parameter.
Firstly, rather than using a varchar(MAX) for #Columns I suggest a table type object:
CREATE TYPE dbo.ObjectList (ObjectName sysname);
sysname is a synonym of nvarchar(128) NOT NULL; and is the data type used for object names in SQL Server. You'll then need to INSERT the names of the columns into a declared table type parameter; one row for each Column Name
Then we can safely inject and parametrise your query:
--Parameters
DECLARE #Columns dbo.ObjectList,
#IdxColumn sysname, --sysname as well
#Limit int; --not varchar
--Variables needed in the SQL:
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = N'SELECT TOP (#Limit)' + #CRLF +
N' ' + QUOTENAME(#IdxColumn) + N',' + #CRLF +
STUFF((SELECT N',' + #CRLF +
N' ' + QUOTENAME(C.ObjectName)
FROM #Columns C
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + #CRLF +
N'FROM dbo.[Table]' + #CRLF + --Should dbo.[Table] also not be safely injected?
N'WHERE ' +
STUFF((SELECT #CRLF +
N' OR ' + QUOTENAME(C.ObjectName) + N' IS NOT NULL'
FROM #Columns C
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,8,N'') + #CRLF +
N'ORDER BY ' + QUOTENAME(#IdxColumn) + N' ASC;'
EXEC sp_executesql #SQL, N'#Limit int', #Limit;

Moving result from 1:n query to repeating columns

I would like to achieve the following from a result of a 1:n join using T-sql
Surname | Givename |..Address | City
Name1....| Givename1.|..Addr11...| City11
Name1....| Givename1.|..Addr12...| City12
Name2....| Givename2.|..Addr21...| City21
Name2....| Givename2.|..Addr22...| City22
Name2....| Givename2.|..Addr23...| City23
TO:
Surname | Givename.. | Address | City... | Address | City... | Address | City
Name1....| Givename1...| Addr11....| City11. | Addr12....| City12. |
Name2....| Givename2...| Addr21....| City21. | Addr22....| City22. | Addr23....| City23
I not care about repeating columnames. Up if there is a soultion with numbers in the repeating columns it would be fine too.
Thanks
In my opinion Pivot is not a solution in this case. Because the column name should repat, and in pivot, cell values are moved to column names, also is unlike pivot no aggregate function involved.
In my thought, the following query will handle your issue. However the SQL Server has column number limit for tables.
Columns per table 1,024 Tables that include sparse column sets
include up to 30,000 columns. See sparse column sets.
You should take this considiration for your data.
DROP TABLE IF EXISTS #Test
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE #Test(Surname VARCHAR(100) , GivenName VARCHAR(200),
Adress VARCHAR(100),City VARCHAR(100))
INSERT INTO #Test
VALUES
('Name1','Givename1','Addr11','City11'),
('Name1','Givename1','Addr12','City12'),
('Name2','Givename2','Addr21','City21'),
('Name2','Givename2','Addr22','City21'),
('Name2','Givename2','Addr23','City23')
,('Name5','Givename5','Addr51','City51'),
('Name5','Givename5','Addr52','City52'),
('Name5','Givename5','Addr53','City53'),
('Name5','Givename5','Addr54','City54'),
('Name3','Givename3','Addr31','City31')
DECLARE #Counter AS INT=1
DECLARE #Max AS INT
DECLARE #SQL AS VARCHAR(MAX)
SELECT #Max= MAX(DetMax) FROM
(
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS DetMax FROM #Test
) AS TMP
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE ##PivotUnlimited (Surname VARCHAR(100),GivenName VARCHAR(100))
WHILE #Counter <=#Max
BEGIN
SET #SQL= 'ALTER TABLE ##PivotUnlimited ADD ADDR' + CONVERT(VARCHAR,#Counter) + ' VARCHAR(100)'
EXEC(#SQL)
SET #SQL= 'ALTER TABLE ##PivotUnlimited ADD City' + CONVERT(VARCHAR,#Counter) + ' VARCHAR(100)'
EXEC(#SQL)
SET #Counter=#Counter+1
END
INSERT INTO ##PivotUnlimited (Surname,GivenName)
SELECT DISTINCT Surname , GivenName FROM #Test
DECLARE #Name AS VARCHAR(100)
DECLARE cursorT CURSOR
FOR
SELECT DISTINCT Surname from #test
OPEN cursorT
FETCH NEXT FROM cursorT INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #CounterCursor AS INT=1
DECLARE #MaxCursort AS INT =0
DECLARE #UpdateSQL AS VARCHAR(MAX)
DECLARE #UptAdr AS VARCHAR(100)
DECLARE #UptCity AS VARCHAR(100)
SELECT #MaxCursort=RowNumber FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber FROM #Test
WHERE Surname=#Name
) AS TMP_TBL
WHILE #CounterCursor<= #MaxCursort
BEGIN
SELECT #UptAdr=Adress ,#UptCity=City FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber,* FROM #Test
) AS TMP_TBL WHERE RowNumber=#CounterCursor and Surname=#Name
SET #UpdateSQL= 'UPDATE ##PivotUnlimited SET ADDR' + CONVERT(VARCHAR,#CounterCursor) + ' = ' + '''' + #UptAdr +'''' + ' , '
+ ' City' + CONVERT(VARCHAR,#CounterCursor) + ' = ' + '''' + #UptCity +'''' + ' WHERE Surname = ' + '''' + #Name + ''''
EXEC (#UpdateSQL)
SET #CounterCursor=#CounterCursor+1
END
FETCH NEXT FROM cursorT INTO #Name
END
CLOSE cursorT
DEALLOCATE cursorT
SELECT * FROM ##PivotUnlimited
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Surname | GivenName | ADDR1 | City1 | ADDR2 | City2 | ADDR3 | City3 | ADDR4 | City4 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Name1 | Givename1 | Addr11 | City11 | Addr12 | City12 | NULL | NULL | NULL | NULL |
| Name2 | Givename2 | Addr21 | City21 | Addr22 | City21 | Addr23 | City23 | NULL | NULL |
| Name3 | Givename3 | Addr31 | City31 | NULL | NULL | NULL | NULL | NULL | NULL |
| Name5 | Givename5 | Addr51 | City51 | Addr52 | City52 | Addr53 | City53 | Addr54 | City54 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+

SQL separate for stored procedure

About SQL Server Management Studio stored procedure.
The following variables '|' I want to separate it from. How can I do it?
'628391|28100|8304|3|1201129|12|Kg|M01|SERIOUSLY CHUNKY WOOL'
'627452|70462|618|60|100059|72|Ad|M01|THICK & QUICK STRIPES'
'617213|99233|89|10|18754|12|Kg|M01|FASHION KC ARAN 400'
You can use the following query
DECLARE #PL AS VARCHAR(MAX)='628391|28100|8304|3|1201129|12|Kg|M01|SERIOUSLY CHUNKY WOOL'
SELECT value FROM string_split(#PL,'|')
+-----------------------+
| value |
+-----------------------+
| 628391 |
| 28100 |
| 8304 |
| 3 |
| 1201129 |
| 12 |
| Kg |
| M01 |
| SERIOUSLY CHUNKY WOOL |
+-----------------------+
EDIT
DROP TABLE IF EXISTS TestStrList
DECLARE #query AS NVARCHAR(MAX)
DECLARE #PL AS VARCHAR(MAX)='628391|28100|8304|3|1201129|12|Kg|M01|SERIOUSLY CHUNKY WOOL'
DECLARE #cOL AS VARCHAR(MAX)
SELECT value INTO
TestStrList FROM string_split(#PL,'|')
select #cOL = STUFF((SELECT ',' + QUOTENAME(value)
FROM TestStrList
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cOL + N' from
(
select value
from TestStrList
) x
pivot
(
max(value)
for value in (' + #cOL + N')
) p '
exec sp_executesql #query;
+--------+-------+------+---+---------+----+----+-----+-----------------------+
| 628391 | 28100 | 8304 | 3 | 1201129 | 12 | Kg | M01 | SERIOUSLY CHUNKY WOOL |
+--------+-------+------+---+---------+----+----+-----+-----------------------+
| 628391 | 28100 | 8304 | 3 | 1201129 | 12 | Kg | M01 | SERIOUSLY CHUNKY WOOL |
+--------+-------+------+---+---------+----+----+-----+-----------------------+
I'm not sure what you mean with "seperate it" but the following SQL QUERY might be helpful for you.
DECLARE #text VARCHAR(200) = '617213|99233|89|10|18754|12|Kg|M01|FASHION KC ARAN 400'
WHILE 1 = 1
BEGIN
DECLARE #index INT = CHARINDEX('|', #text, 1)
IF #index = 0
RETURN
SELECT LEFT(#text, #index - 1)
SET #text = SUBSTRING(#text, #index + 1, LEN(#text) - #index)
END
Basically, the code with using CHARINDEX, is trying to find out the index of the first pipe (from left) in the text. After finding the index, it's applies a SUBSTRING to get exact text.

Merge two rows in SQL with only one column being different

Assuming I have a table containing the following information:
FK | Field1 | Field2
---+--------+--------
4 | 103 | 5836
4 | 103 | 5835
FK | Field1 | Field2 | Field2A
---+--------+--------+--------
4 | 103 | 5836 | 5835
Thanks
i think you really need PIVOT, but for an exact dataset in the question, you can follow an approach like below, it's kinda weird and in T-SQl:
declare #a as int
declare #b as int
declare #c as int
declare #query Varchar(Max)
set #query = 'Select 4,103'
DECLARE curs CURSOR FOR
select * From
(select 4 as a , 103 as b , 5836 as c
Union select 4 as a , 103 as b , 5835 as c) as res
OPEN curs
FETCH NEXT FROM curs
INTO #a,#b,#c
WHILE ##FETCH_STATUS = 0
BEGIN
set #query = #query + ','+cast(#c as varchar)
FETCH NEXT FROM curs
INTO #a,#b,#c
END
CLOSE curs;
DEALLOCATE curs;
EXEC(#query)