Create different tables from 1 source table using Dynamic SQL - sql

I have a sourcetable, from which I want to create different tables, using dynamic SQL.
Sourcetable:
ACCP_AcceptantID TransactionID Descrption Period AcceptantNumber
1 12 A 201801 16
1 13 AA 201801 16
2 21 B 201801 22
2 46 BB 201801 22
3 31 C 201801 54
3 38 CC 201801 54
4 94 D 201801 62
4 96 DD 201801 62
To be able to use a WHILE Loop to select each acceptant, I created a Table Acceptants:
SELECT DISTINCT ACCP_AcceptantNr
INTO Acceptants
FROM Sourcetable
ALTER TABLE #TussentabelAcceptanten ADD ID INT IDENTITY
ACCP_AcceptantNr ID
16 1
22 2
54 3
62 4
Desired Result (for each acceptantID, own table with content):
ACCP_AcceptantID TransactionID Descrption Period AcceptantNumber
1 12 A 201801 16
1 13 AA 201801 16
My query attempt:
DECLARE #SQL NVARCHAR(MAX),
#Acceptant NVARCHAR(40),
#Row INT = 1
WHILE #Row <= ( SELECT MAX(ID) FROM Acceptants)
BEGIN
SELECT #Acceptant = ACCP_AcceptantNr FROM Acceptants
SET #SQL = 'SELECT *
INTO MyDatabase.dbo.'+ Period + #Acceptant'
FROM #SourceTable
WHERE ACCP_AcceptantNr = '+ #Acceptant''
EXEC (#SQL)
SET #Row = #Row + 1
SET #SQL = ''
END
Error message: Incorrect syntax near '
Dynamic SQL always gets the better of me. I just don't get where to place the quotes. Suggestions would be great. Thanks.

You are missing the + symbols
SET #SQL = 'SELECT *
INTO MyDatabase.dbo.'+ Period + #Acceptant+'--Added +
FROM #SourceTable
WHERE ACCP_AcceptantNr = '+ #Acceptant -- Removed ''
Since you are Giving Period without an # symbol, I assume it is a column from some table, so add a selet from that table otherwise this will throw an error.
Like this
SELECT #SQL = 'SELECT *
INTO MyDatabase.dbo.'+ Period + #Acceptant+'--Added +
FROM #SourceTable
WHERE ACCP_AcceptantNr = '+ #Acceptant -- Removed ''
FROM YourTableName

Related

Sum of Current + Previous X Nth Rows

I am looking to find the sum of the current + the last X Nth Rows. I am able to do this with the following query, however it is not very scalable.
SELECT [id], [amount] + LAG([amount],6) OVER(ORDER BY [id]) + LAG([amount],12) OVER(ORDER BY [id]) + LAG([amount],18) OVER(ORDER BY [id])
If this example, I'm finding the current value of "amount", plus the last 3 "amounts" split 6 apart:
X = 3
N = 6
I will be using these within dynamic queries and would prefer not to build such a complex query each time. There could be many "lags" in some of the queries. Is there another way to write this query that would be more scalable?
SOURCE DATA
ID
Amount
1
107.35
2
105.41
3
104.63
4
106.7
5
108.7
6
110.21
7
108.8
8
108.91
9
108.5
10
106.66
11
105.2
12
106.5
13
108.27
14
109.72
15
111.53
16
112.8
17
109.03
18
115.31
19
115.56
20
116.85
21
116.08
22
117.61
23
118.31
24
119.25
25
118.45
26
118.43
27
120.16
28
122.5
29
125.57
30
125.65
EXPECTED RESULTS
ID
SUM OF LAST 4
1
NULL
2
NULL
3
NULL
4
NULL
5
NULL
6
NULL
7
NULL
8
NULL
9
NULL
10
NULL
11
NULL
12
NULL
13
NULL
14
NULL
15
NULL
16
NULL
17
NULL
18
NULL
19
439.98
20
440.89
21
440.74
22
443.77
23
441.24
24
451.27
25
451.08
26
453.91
27
456.27
28
459.57
29
458.11
30
466.71
At a best guess, it seems like what you want is something like this:
DECLARE #X int = 3,
#N int = 6;
SELECT YT.ID,
YT.Amount,
CASE WHEN ROW_NUMBER() OVER (PARTITION BY G.Grp ORDER BY ID) < #X+1 THEN NULL
ELSE SUM(Amount) OVER (PARTITION BY G.Grp ORDER BY ID
ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
END
FROM dbo.YourTable YT
CROSS APPLY (VALUES(ID % #N))G(Grp)
ORDER BY YT.ID;
You'll note, however, that the 3 is hardcoded in one place, as you cannot use a variable for the ROWS BETWEEN clause. If you need to parametrise this, you'll need to use dynamic SQL:
DECLARE #X int = 3,
#N int = 6;
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = CONCAT(N'SELECT YT.ID,', #CRLF,
N' YT.Amount,', #CRLF,
N' CASE WHEN ROW_NUMBER() OVER (PARTITION BY G.Grp ORDER BY ID) < #X+1 THEN NULL', #CRLF,
N' ELSE SUM(Amount) OVER (PARTITION BY G.Grp ORDER BY ID', #CRLF,
N' ROWS BETWEEN ',#X,N' PRECEDING AND CURRENT ROW)', #CRLF, --I don't like injecting raw values, but if #X is an int, it is "safe"
N' END', #CRLF,
N'FROM dbo.YourTable YT', #CRLF,
N' CROSS APPLY (VALUES(ID % #N))G(Grp)', #CRLF,
N'ORDER BY YT.ID;');
PRINT #SQL; --Your best debugging friend
EXEC sys.sp_executesql #SQL, N'#X int, #N int', #X, #N;
db<>fiddle

Reformatting SQL output

I have data that looks like this
Name XX YY
alpha 10 77
beta 10 90
alpha 20 72
beta 20 91
alpha 30 75
beta 30 94
alpha 40 76
beta 40 95
If I use
select * from scores order by Name, XX
I will get
Name XX YY
alpha 10 77
alpha 20 72
alpha 30 75
alpha 40 76
beta 10 90
beta 20 91
beta 30 94
beta 40 95
At the moment, I'm retrieving the data in this form and using some C coding to format it like
Name xx=10 xx=20 xx=30 xx=40
alpha 77 72 75 76
beta 90 91 94 95
Assuming that there will always be entries for 10, 20, 30, 40 for every name, is something like this possible in SQL without creating a new table like in SQL Reformatting table columns
You need to use PIVOT to get your desired results. Before using PIVOT, some customization required in your value in column XX so that the final column output can meet your expectation.
SELECT * FROM
(
SELECT Name,'XX='+CAST(XX AS VARCHAR) XX,YY
FROM your_table
)AS P
PIVOT(
SUM(YY)
FOR XX IN ([XX=10],[XX=20],[XX=30],[XX=40])
) PP
Output-
Name XX=10 XX=20 XX=30 XX=40
alpha 77 72 75 76
beta 90 91 94 95
The same output can be also achieved with this following query-
SELECT Name,
[10] AS [XX=10],
[20] AS [XX=20],
[30] AS [XX=30],
[40] AS [XX=40]
FROM
(
SELECT Name, XX,YY
FROM your_table
)AS P
PIVOT(
SUM(YY)
FOR XX IN ([10],[20],[30],[40])
) PP
You could use dynamic PIVOT to achieve the same result which would be more robust,
CREATE TABLE #table1 (Name varchar(100), XX INT, YY INT)
INSERT INTO #table1 VALUES
('alpha',10,77),
('beta',10,90),
('alpha',20,72),
('beta',20,91),
('alpha',30,75),
('beta',30,94),
('alpha',40,76),
('beta',40,95)
DECLARE #pvt NVARCHAR(MAX) = '';
DECLARE #dynamicCol NVARCHAR(MAX) = '';
SELECT #pvt += ', ' +QUOTENAME([XX]) FROM #table1 GROUP BY [XX];
SELECT #dynamicCol += ', ' +QUOTENAME([XX]) + ' AS ' + QUOTENAME('XX=' + CAST([XX] AS VARCHAR(25))) FROM #table1 GROUP BY [XX];
SET #pvt = STUFF(#pvt,1,1,'')
SET #dynamicCol = STUFF(#dynamicCol,1,1,'')
EXEC ('
SELECT [Name],' + #dynamicCol+'
FROM #table1 a
PIVOT
(
SUM([YY])
FOR [XX] IN ('+ #pvt+')
) PIV');
The result is as below,
Name XX=10 XX=20 XX=30 XX=40
alpha 77 72 75 76
beta 90 91 94 95
Another solution with case
SELECT Name
,SUM(CASE when XX = '10' then YY else 0 END) AS 'xx=10'
,SUM( CASE when XX = '20' then YY else 0 END) AS 'xx=20'
,SUM( CASE when XX = '30' then YY else 0 END) AS 'xx=30'
,SUM( CASE when XX = '40' then YY else 0 END) AS 'xx=40'
FROM temp_0
group by Name

SQL Server : Transpose rows to columns

I am trying to do transpose data. The number of columns are not fixed(i.e. selected ShiftNames are not fixed). Here is my input data.
Date_time ShiftName Consumption
28-07-2016 Shift 1 20
28-07-2016 Shift 2 21
28-07-2016 Shift 3 22
29-07-2016 Shift 1 30
29-07-2016 Shift 2 31
29-07-2016 Shift 3 32
30-07-2016 Shift 1 40
30-07-2016 Shift 2 41
30-07-2016 Shift 3 42
And the output will be like this
Shift 1 Shift 2 Shift 3 Date_Time
20 21 23 28-07-2016
30 31 32 29-07-2016
40 41 42 30-07-2016
You can do this with an pivot. Here is an example:
Test data:
DECLARE #temp TABLE(Date_time varchar(100), ShiftName VARCHAR(100), Consumption INT)
INSERT INTO #temp
VALUES
('28-07-2016','Shift 1',20),
('28-07-2016','Shift 2',21),
('28-07-2016','Shift 3',22),
('29-07-2016','Shift 1',30),
('29-07-2016','Shift 2',31),
('29-07-2016','Shift 3',32),
('30-07-2016','Shift 1',40),
('30-07-2016','Shift 2',41),
('30-07-2016','Shift 3',42)
Pivot:
SELECT
*
FROM
(
SELECT
Date_time,
ShiftName,
Consumption
FROM
#temp
) AS sourceTable
PIVOT
(
SUM(Consumption)
FOR ShiftName IN ([Shift 1],[Shift 2],[Shift 3])
) AS pvt
Result:
Date_time Shift 1 Shift 2 Shift 3
28-07-2016 20 21 22
29-07-2016 30 31 32
30-07-2016 40 41 42
Reference:
Using PIVOT and UNPIVOT
Since the shiftName is dynamic,use this dynamic query
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT
#cols = STUFF((SELECT distinct ',' + QUOTENAME(ShiftName )
FROM
#temp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #query = 'SELECT * FROM
(
SELECT * FROM #temp
) x
PIVOT
(
Sum(consumption)
FOR ShiftName IN (' + #cols + ')
) p '
EXECUTE(#query);

PIVOT in SQL Server 2012 - new to SQL [duplicate]

This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 6 years ago.
I am having some trouble with the next situation: I need to select 4 position for a statement and I need this positions to be pivoted as columns. The database is structured as: StatementId 1, PositionId 2, RepCurrValue 3. For example for StatementId = 55 and for the positions = 58 OR 62 OR 67 OR 82 the result is:
1 2 3
-----------------
55 58 146,8000
55 62 59,9800
55 67 800,0500
55 82 136,7600
and I want it to be
1 58 62 67 82
---------------------------------------
55 146,8000 59,9800 800,0500 136,7600
Thank you very much for your support.
I did this exercise with PIVOT table that could be help you, considering the column headings equal to the contents of the field [2] and NOT providing repeated values ​​in column [2]:
DECLARE #cols AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',[' + convert(nvarchar,(t.[2])) + ']' AS ID
FROM TB_1 t
FOR XML PATH(''), TYPE).value('.', 'varchar(max)'),1,1, '')
DECLARE #query AS NVARCHAR(MAX);
SET #query = N'SELECT p.[1],' + #cols + N' from
(
SELECT [1],[2],[3] FROM TB_1
) x
pivot
(
max([3])
for [2] in (' + #cols + N')
) p
'
exec sp_executesql #query;
below the result obtained by adding an additional StatementId (56) and new different positions (90,91) associated with StatementId (56)
1 58 62 67 82 90 91
55 146,8000 59,9800 800,0500 136,7600 NULL NULL
56 NULL NULL NULL NULL 185,74 185,74
a non-dynamic solution can be:
select *
from
(
SELECT [1],[2],[3] FROM TB_1
) x
pivot
(
max([3])
for [2] in ([58] , [62] , [67] , [82] )
) p

SQL Pivot Dynamic Columns

I have a query that generates results for learners on a specific course showing whether or not they have completed a module. Learners can take different modules from each other.
SELECT LearnerID,
UnitID,
CASE WHEN (SUM(Total - [Total Achieved])) = 0 THEN 'Yes' ELSE 'No' END AS Completed
FROM dbo.LMS_Achieved_Standards_Report
GROUP BY CourseID, LearnerID, UnitID
The results look like this
LearnerID UnitID Completed
15 15 Yes
15 28 No
28 28 Yes
116 150 Yes
79 12 No
69 34 Yes
69 15 No
I need it to look like this:
LearnerID Unit 15 Unit 28 Unit 150 Unit 12 Unit 34
15 Yes No
28 Yes
116 Yes
79 Yes
69 No Yes
The other factor as already stated is that they can all take different units so I can't create a PIVOT with set column headings.
Any ideas?
try this;
select * into #tbl from (select 'cust1' as key1, 'Red'as Type
union select 'cust1' as key1, 'Blue'as Type
union select 'cust1' as key1, 'Yellow'as Type
union select 'cust2' as key1, 'Red'as Type
union select 'cust2' as key1, 'Blue'as Type
union select 'cust2' as key1, 'Green'as Type) as dd
declare #strsql as nvarchar(max)
declare #columns as nvarchar(max)
set #columns = (select stuff((select distinct ',['+Type+']' from #tbl FOR XML PATH('')),1,1,''))
set #strsql = 'select key1,'+#columns + 'from (select * from #tbl) as p pivot (count(p.Type) For p.Type in ('+#columns+'))as pivottable'
--set #strsql = 'select
EXECUTE sp_executesql #strsql