Unpivot the columns into rows - sql-server

I have one row with an unknown number of columns. I need to unpivot all those columns into one column. Here is an example. I start with this table
select 1 as c1, 2 as c2, 3 as c3
into tempP
If we select this table the result will be
c1 c2 c3
1 2 3
I want the result to be this
new_name
1
2
3
Also, remember that I don't know if I will have 3 columns. I might have 100 columns, but the number of rows will always be 1. Thanks.

As Bluefeet mentioned in your comments section you will need an UNPIVOT query for this not a Pivot query.
One thing you need to be careful about, the data type should be the same for all the columns you are Unpivoting.
Something like this....
DECLARE #TABLE TABLE(c1 INT , c2 INT, c3 INT)
INSERT INTO #TABLE VALUES
(1, 2, 3),
(10, 20, 30)
SELECT NewColumn
FROM #TABLE
UNPIVOT (NewColumn FOR allcols IN ([c1],[c2],[c3]) ) up
Result:
NewColumn
1
2
3
10
20
30

Related

How to update rows based on one field/column on two tables

I want to update one table using another table on field "Id" such that it wont create duplicates
let say my first table is Table1 and second table is Table2 . I would like to update the row in Table1 from Table2 when the Id is matching
I am aware of using UNION function but this applies to entire columns where I only need to consider a single column. https://docs.snowflake.com/en/sql-reference/operators-query.html#union-all
Example of my Tables
Table1
Id name number value
1 a 8 100
2 b 8 100
3 c 8 100
4 d 8 100
Table2
Id name number value
3 c 8 99
4 d 6 100
5 e 7 100
Expected output
Id name number value
1 a 8 100
2 b 8 100
3 c 8 99
4 d 6 100
5 e 7 100
Please note that in the output table row with Id 3,4 has be updated and new Id 5 is inserted.
PS: It would be better if someone could provide me the select statement to get the output table.
The constuct you are searching for is called MERGE:
CREATE OR REPLACE TABLE trg(Id INT, name VARCHAR, number INT, value INT)
AS SELECT 1 ,'a', 8, 100
UNION SELECT 2 ,'b', 8, 100
UNION SELECT 3 ,'c', 8, 100
UNION SELECT 4 ,'d', 8, 100;
CREATE OR REPLACE TABLE src(Id INT, name VARCHAR, number INT, value INT)
AS SELECT 3 ,'c', 8, 99
UNION SELECT 4 ,'d', 6, 100
UNION SELECT 5 ,'e', 7, 100;
Query:
MERGE INTO trg
USING src
ON trg.Id = src.Id
WHEN MATCHED THEN UPDATE SET name = src.name,
number = src.number,
value = src.value
WHEN NOT MATCHED THEN INSERT (ID, name, number, value)
VALUES (src.Id, src.name, src.number, src.value);
SELECT * FROM trg;
Output:
EDIT:
PS: It would be better if someone could provide me the select statement to get the output table.
UNION ALL combined with QUALIFY could be used:
WITH cte AS (
SELECT *, 1 AS priority FROM trg
UNION ALL
SELECT *, 0 AS priority FROM src
)
SELECT Id, Name, Number, Value
FROM cte
QUALIFY ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Priority) = 1
ORDER BY Id;

SQL Server - recursively calculated column

I need to calculate a column based of a seed row where each row's value uses the "previous" row's values. I feel like this should be a recursive query but I can't quite wrap my head around it.
To illustrate:
BOP EOP IN OUT Wk_Num
--------------------------------------
6 4 10 12 1
? ? 2 6 2
? ? 7 5 3
... ... ... ... ...
So the next row's BOP and EOP columns need to be calculated using the seed row. The IN and OUT values are already present in the table.
BOP = (previous row's EOP)
EOP = (Previous row's EOP) + IN - OUT [where IN and OUT are from the current row)
OUTPUT of this example should look like:
BOP EOP IN OUT Wk_num
-------------------------------------
6 4 10 12 1
4 0 2 6 2
0 2 7 5 3
2 6 4 0 4
... ... ... ... ...
You can use a Recursive CTE for this;
WITH RecursiveCTE AS (
-- Base Case
SELECT
BOP,
EOP,
[IN],
[OUT],
[WK_Num]
FROM [someTable]
WHERE BOP IS NOT NULL
UNION ALL
SELECT
r.EOP AS BOP,
r.EOP + r2.[In] - r2.[Out] AS EOP,
r2.[IN],
r2.[OUT],
r2.[WK_Num]
FROM [someTable] r2
INNER JOIN [RecursiveCTE] r
ON r2.[Wk_Num] = r.[Wk_Num] + 1
)
SELECT * FROM RecursiveCTE
Here is a SQL Fiddle: http://sqlfiddle.com/#!18/e041f/1
You basically define the base case as the first row (by saying the row with BOP != null), then join to each following week with the Wk_Num + 1 join, and reference the previous rows values
You can use SUM OVER like this:
DECLARE #TempTable AS TABLE(T_In INT, T_Out INT, T_WeekNum INT)
INSERT INTO #TempTable VALUES (6, 0, 0)
INSERT INTO #TempTable VALUES (10, 12, 1)
INSERT INTO #TempTable VALUES (2, 6, 2)
INSERT INTO #TempTable VALUES (7, 5, 3)
INSERT INTO #TempTable VALUES (4, 0, 4)
SELECT
SUM(T_In - T_Out) OVER(ORDER BY T_WeekNum ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - T_In + T_Out AS T_Bop,
SUM(T_In - T_Out) OVER(ORDER BY T_WeekNum ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS T_Eop,
T_In,
T_Out,
T_WeekNum
FROM #TempTable
The calculation is the same for BOP and EOP but the values from the current row are subtracted from the BOP column to get the value from the last row.

FETCH specific number of primary key rows

I have an SQL SELECT that left-joins several tables together, which results in an output with redundant data.
Example query:
SELECT
A.ID, B.ID
FROM A
LEFT JOIN B ON B.ParentID=A.ID
FETCH NEXT 4 ROWS ONLY
Example output:
A.ID B.ID
1 10
1 20
2 30
2 40
My problem is that I want to limit the number of rows from the A table, not from the actual output. In short, I would like to have an output like this when I ask for 4 rows:
A.ID B.ID
1 10
1 20
2 30
2 40
3 50
3 60
4 70
4 80
Any advice?
UPDATE:
Here is a fiddle that could help explaining the problem:
Fiddle
i have applied query on actual data, use sub query to get top 4 result.
declare #temp table
(aId int, bId int)
insert into #temp
values
(1,10),
(1,20),
(2,30),
(2,40),
(3,50),
(3,60),
(4,70),
(4,80),
(5,90),
(6,100)
select * from #temp
where aId in
(select distinct top 4 aId from #temp where aId > 1)

UPDATE with non-CLR product aggregate results in off-by-one

I was answering another question and ran into a strange outcome - the output of a product aggregate (without CLR) was different when used in a SELECT vs UPDATE.
This is simplified from the original question to minimally reproduce the problem:
GroupKey RowIndex A
----------- ----------- -----------
25 1 5
25 2 6
25 3 NULL
26 1 3
26 2 4
26 3 NULL
The goal is for each group key to update the A column of each row with a RowIndex = 3 to the product of the A columns of each row with RowIndex IN (1, 2), so this would produce the following changes:
GroupKey RowIndex A
----------- ----------- -----------
25 3 30
26 3 12
So this is the code I used:
UPDATE T SET
A = Products.Product
FROM #Table T
INNER JOIN (
SELECT
GroupKey,
EXP(SUM(LOG(A))) AS Product
FROM #Table
WHERE RowIndex IN (1, 2)
GROUP BY
GroupKey
) Products
ON Products.GroupKey = T.GroupKey
WHERE T.RowIndex = 3
SELECT * FROM #Table WHERE RowIndex = 3
Which then produced the off-by-one results:
GroupKey RowIndex A
----------- ----------- -----------
25 3 29
26 3 12
If I just run the sub-query, I see the correct values.
GroupKey Product
----------- ----------------------
25 30
26 12
Here's the full script to make it easy to play with. I can't figure out where the off-by-one is coming from.
DECLARE #Table TABLE (GroupKey INT, RowIndex INT, A INT)
INSERT #Table VALUES (25, 1, 5), (25, 2, 6), (25, 3, NULL), (26, 1, 3), (26, 2, 4), (26, 3, NULL)
SELECT * FROM #Table
SELECT
GroupKey,
EXP(SUM(LOG(A))) AS Product
FROM #Table
WHERE RowIndex IN (1, 2)
GROUP BY
GroupKey
UPDATE T SET
A = Products.Product
FROM #Table T
INNER JOIN (
SELECT
GroupKey,
EXP(SUM(LOG(A))) AS Product
FROM #Table
WHERE RowIndex IN (1, 2)
GROUP BY
GroupKey
) Products
ON Products.GroupKey = T.GroupKey
WHERE T.RowIndex = 3
SELECT * FROM #Table WHERE RowIndex = 3
Here are some references I came across:
Non-CLR Aggregate: http://michaeljswart.com/2011/03/the-aggregate-function-product/
Original question: Set one row fields as a multiplication of 2 others
I'd say that this cute "PRODUCT" aggregate is inherently unreliable if you want to work with ints - EXP and LOG are only defined against the float type and so we get rounding errors creeping in.
Why they're not consistently appearing, I couldn't say, except to suggest that different queries may cause changes in evaluation orders.
As a simpler example of how this can go wrong:
select CAST(EXP(LOG(5)) as int)
Can produce 4. EXP and LOG together will produce a value that is just less than 5, but of course when converting to int, SQL Server always truncates rather than applying any rounding.

Expand row results based on a value in column (with iterator)

Need help from you all in writing up this query. Running SQL 2005 Standard edition.
I have a basic query that gets a subset of records from a table where the record_Count is greater then 1.
SELECT *
FROM Table_Records
WHERE Record_Count > 1
This query gives me a result set of, say:
TableRecords_ID Record_Desc Record_Count
123 XYZ 3
456 PQR 2
The above query needs to be modified so that each record appears as many times as the Record_Count and has its iteration number with it, as a value. So the new query should return results as follows:
TableRecords_ID Record_Desc Record_Count Rec_Iteration
123 XYZ 3 1
123 XYZ 3 2
123 XYZ 3 3
456 PQR 2 1
456 PQR 2 2
Could anyone help we write this query up? appreciate the help.
Clarification: Rec_Iteration column is a sub representation of the Record_Count. Basically, since there are three Record_Count for XYZ description thus three rows were returned with the Rec_Iteration representing the Row one , two and three respectively.
You can use a recursive CTE for this query. Below I use a table variable #T instead of your table Table_Records.
declare #T table(TableRecords_ID int,Record_Desc varchar(3), Record_Count int)
insert into #T
select 123, 'XYZ', 3 union all
select 456, 'PQR', 2
;with cte as
(
select TableRecords_ID,
Record_Desc,
Record_Count,
1 as Rec_Iteration
from #T
where Record_Count > 1
union all
select TableRecords_ID,
Record_Desc,
Record_Count,
Rec_Iteration + 1
from cte
where Rec_Iteration < Record_Count
)
select TableRecords_ID,
Record_Desc,
Record_Count,
Rec_Iteration
from cte
order by TableRecords_ID,
Rec_Iteration

Resources