this is driving me a bit nuts. I'll explain a simplified version of my problem. I have two tables, source and destination:
CREATE TABLE AMG_TDest(
ID INT,
Value1 INT,
Value2 INT,
Value3 INT,
Value4 INT)
CREATE TABLE AMG_TSource(
ID INT,
RowNumber INT,
Value INT)
INSERT INTO AMG_TDest VALUES (1, 0, 0, 0, 0), (2, 0, 0, 0, 0)
INSERT INTO AMG_TSource VALUES (1, 1, 1), (1, 2, 2), (1, 3, 3), (1, 4, 4), (2, 1, 10), (2, 2, 20), (2, 3, 30), (2, 4, 40)
I want to update Value1, Value2, Value3 and Value4 in Destination table depending on TSource.RowNumber.
In the end what I want to get as a result is this on Destination table:
ID V1 V2 V3 V4
1 1 2 3 4
2 10 20 30 40
I tried this (with some variations)
UPDATE AMG_TDest
SET
Value1 = CASE WHEN S.RowNumber = 1 THEN COALESCE(S.Value, 0) ELSE Value1 END,
Value2 = CASE WHEN S.RowNumber = 2 THEN COALESCE(S.Value, 0) ELSE Value2 END,
Value3 = CASE WHEN S.RowNumber = 3 THEN COALESCE(S.Value, 0) ELSE Value3 END,
Value4 = CASE WHEN S.RowNumber = 4 THEN COALESCE(S.Value, 0) ELSE Value4 END
FROM ( SELECT * FROM AMG_TSource ) AS S
INNER JOIN AMG_TDest D ON D.ID = S.ID
It just updates the Value1 from first row and Value4 from last row. I've been battling with this for some hours now and I can't make it work. If anyone has suggestions I'm really thankful.
Here's a method using a PIVOT
;WITH cteX
AS(
SELECT PVT.ID
, PVT.Value4
, PVT.Value3
, PVT.Value2
, PVT.Value1
FROM
(
SELECT S.ID
, RN ='Value' + CAST(S.RowNumber AS varchar(10))
, S.[Value]
FROM dbo.AMG_TSource S
) X
PIVOT
(
MAX(Value) FOR RN IN ([Value1],[Value2],[Value3],[Value4])
) PVT
)
UPDATE D
SET D.Value1 = X.Value1
, D.Value2 = X.Value2
, D.Value3 = X.Value3
, D.Value4 = X.Value4
FROM
dbo.AMG_TDest D
INNER JOIN
cteX X ON X.ID = D.ID
The Pivot chamges the Source dataset like so
ID Value4 Value3 Value2 Value1
1 4 3 2 1
2 40 30 20 10
Then all you need to is then join on the ID column
for the update to the destination table
Related
There are two table:
Table a:
id name b_id1 b_id2 b_id3 b_id4
1 a 10 8 null null
2 b 3 4 8 10
3 c 10 5 4 null
Table B
b_id title
3 Value3
4 Value4
5 Value 5
8 Value 8
10 Value
Table A has F.K on b_id1,b_id2,b_id3,b_id4 to table B on b_id cloumn,
We are going to group on Title and count it.
something like following result:
Title Count
Value3 1
Value4 2
Value5 1
Value8 2
Value10 3
Null 3
Full working example:
DECLARE #Table1 TABLE
(
[id] INT
,[name] VARCHAR(1)
,[b_id1] INT
,[b_id2] INT
,[b_id3] INT
,[b_id4] INT
);
DECLARE #Table2 TABLE
(
[b_id] INT
,[title] VARCHAR(7)
);
INSERT INTO #Table1 ([id], [name], [b_id1], [b_id2], [b_id3], [b_id4])
VALUES (1, 'a', 10, 8, NULL, NULL)
,(2, 'b', 3, 4, 8, 10)
,(3, 'c', 10, 5, 4, NULL);
INSERT INTO #Table2 ([b_id], [title])
VALUES (3, 'Value3')
,(4, 'Value4')
,(5, 'Value 5')
,(8, 'Value 8')
,(10, 'Value');
SELECT T2.[title]
,COUNT(*)
FROM
(
SELECT [b_id1]
FROM #Table1
UNION ALL
SELECT [b_id2]
FROM #Table1
UNION ALL
SELECT [b_id3]
FROM #Table1
UNION ALL
SELECT [b_id4]
FROM #Table1
) DS
LEFT JOIN #Table2 T2
ON DS.[b_id1] = T2.[b_id]
GROUP BY T2.[title];
One way would be like below:Demo Here
;with cte
as
(select title,count(b_id) as val from table1 t
join
table2 t2
on t.id=t2.b_id
or
t.b_id1=t2.b_id
or
t.b_id2=t2.b_id
or
t.b_id3=t2.b_id
or
t.b_id4=t2.b_id
group by title
)
select * from cte
union all
select null,sum(case
when b_id1 is null then 1 else 0 end)+
sum(case
when b_id2 is null then 1 else 0 end)
+sum(case
when b_id3 is null then 1 else 0 end)
+sum(case
when b_id4 is null then 1 else 0 end)
from table1
output:
Value 3
Value 5 1
Value 8 2
Value3 2
Value4 2
NULL 3
I have table multiple:
CREATE TABLE multiple
(
id int,
Param1 int,
Param2 int,
Param3 int,
Param4 int
);
INSERT INTO multiple VALUES
(1, 1, 2, 3, 0),
(2, 3, 1, 0, 0),
(3, 1, 2, 2, 1);
SELECT * FROM multiple;
I want to achieve with t-SQL new table like this: (Number of rows = Value in Param attributes)
Counter ID TYPE
1 1 Param1
2 1 Param2
3 1 Param2
4 1 Param3
5 1 Param3
6 1 Param3
7 2 Param1
8 2 Param1
9 2 Param1
10 2 Param2
11 3 Param1
12 3 Param2
13 3 Param2
14 3 Param3
15 3 Param3
16 3 Param4
I adder here this text because I have error in editor that it looks like my post is mostly code;
Hey you can use following code to achieve your goal :
CREATE TABLE multiple
(
id int,
Param1 int,
Param2 int,
Param3 int,
Param4 int
);
INSERT INTO multiple VALUES
(1, 1, 2, 3, 0),
(2, 3, 1, 0, 0),
(3, 1, 2, 2, 1);
SELECT * FROM multiple;
CREATE TABLE multiple1
(
ID int,
TYPE VARCHAR(10)
)
DECLARE #id int = 0
WHILE (#id<=(SELECT Count(id) FROM multiple))
BEGIN
DECLARE #Count int = 0
DECLARE #Count1 int = 0
DECLARE #Count2 int = 0
DECLARE #Count3 int = 0
WHILE(#Count<(SELECT Param1 FROM multiple where id = #id))
BEGIN
INSERT INTO multiple1 VALUES ((Select id from multiple where id = #id),'Param1')
SET #Count = #Count + 1
END
WHILE(#Count1<(SELECT Param2 FROM multiple where id = #id))
BEGIN
INSERT INTO multiple1 VALUES ((Select id from multiple where id = #id),'Param2')
SET #Count1 = #Count1 + 1
END
WHILE(#Count2<(SELECT Param3 FROM multiple where id = #id))
BEGIN
INSERT INTO multiple1 VALUES ((Select id from multiple where id = #id),'Param3')
SET #Count2 = #Count2 + 1
END
WHILE(#Count3<(SELECT Param4 FROM multiple where id = #id))
BEGIN
INSERT INTO multiple1 VALUES ((Select id from multiple where id = #id),'Param4')
SET #Count3 = #Count3 + 1
END
SET #id = #id + 1
END
SELECT * FROM multiple1
Have you heard of "tally tables"? They'll make quick work of this. Here is an example solution that uses one. It works by joining on each column where the number is <= the value in the Param attributes, giving you the number of rows you need. Then the id and type are selected.
Note this example uses a tally table that only counts up to 256, so if you need more, you can add an extra level - just be sure to put your tally table into a temp table otherwise it will go from taking a really fast time to execute, to being a really slow time.
CREATE TABLE multiple
(
id int,
Param1 int,
Param2 int,
Param3 int,
Param4 int
);
INSERT INTO multiple VALUES
(1, 1, 2, 3, 0),
(2, 3, 1, 0, 0),
(3, 1, 2, 2, 1);
SELECT * FROM multiple;
-- Tally table known as a "Ben-Gan" style Tally
WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0)
,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4
,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16
,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256
,Tally (n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv3)
SELECT
ROW_NUMBER() OVER (ORDER BY Id) [Counter],
Id,
[Type]
FROM
(
SELECT Id, 'Param1' AS [Type] FROM multiple INNER JOIN Tally ON multiple.Param1 >= Tally.n UNION ALL
SELECT Id, 'Param2' AS [Type] FROM multiple INNER JOIN Tally ON multiple.Param2 >= Tally.n UNION ALL
SELECT Id, 'Param3' AS [Type] FROM multiple INNER JOIN Tally ON multiple.Param3 >= Tally.n UNION ALL
SELECT Id, 'Param4' AS [Type] FROM multiple INNER JOIN Tally ON multiple.Param4 >= Tally.n
) [single]
I have the following table with the following columns.
-------------------------------------
Column1 | Column2 | TotalCount
--------------------------------------
1 1 40
1 2 50
2 1 10
2 2 60
Also, I have another table that is related to Column1 where 1 is X and 2 is Y and same for Column2 where 1 is A and 2 is B
I am trying to come up with a SQL statement that basically gives me some view like...
--------------------
ColumnName | A | B
--------------------
X 40 50
Y 10 60
Any idea how can I achieve that? I've been trying to pivot the data with no luck.
Thanks!
Full working example:
DECLARE #DataSource TABLE
(
[Column1] TINYINT
,[Column2] TINYINT
,[TotalCount] TINYINT
);
INSERT INTO #DataSource ([Column1], [Column2], [TotalCount])
VALUES (1, 1, 40)
,(1, 2, 50)
,(2, 1, 10)
,(2, 2, 60);
SELECT *
FROM
(
SELECT IIF([Column1] = 1, 'X', 'Y') AS [ColumnName]
,IIF([Column2] = 1, 'A', 'B') AS [Column2]
,[TotalCount]
FROM #DataSource
) DS
PIVOT
(
MAX([TotalCount]) FOR [Column2] IN ([A], [B])
) PVT;
Using conditional aggregation:
WITH tbl AS(
SELECT * FROM ( VALUES
(1, 1, 40), (1, 2, 50),
(2, 1, 10), (2, 2, 60)
)t(Column1, Column2, TotalCount)
)
SELECT
ColumnName = CASE WHEN Column1 = 1 THEN 'X' ELSE 'Y' END,
A = MAX(CASE WHEN Column2 = 1 THEN TotalCount END),
B = MAX(CASE WHEN Column2 = 2 THEN TotalCount END)
FROM tbl
GROUP BY Column1
RESULT:
ColumnName A B
---------- ----------- -----------
X 40 50
Y 10 60
I have this table.
Bundles
id | parent_id | quantity
1 | 0 | 1
2 | 1 | 4
3 | 2 | 5
I want to get the total quantity of a bundle with id 3, which is 1 * 4 * 5 = 20 items
Can this be done with a single query?
Here's a solution using CTE:
Setup:
CREATE TABLE Table1
(id int, parent_id int, quantity int)
;
INSERT INTO Table1
(id, parent_id, quantity)
VALUES
(1, 0, 1),
(2, 1, 4),
(3, 2, 5),
(4, 0, 7),
(5, 4, 10)
;
CTE to return total of id=3 and it's parent items:
;WITH myCTE AS
(
SELECT id, parent_id, quantity
FROM Table1
WHERE id = 3
UNION ALL
SELECT T.id, T.parent_id, T.quantity
FROM Table1 T
JOIN myCTE C ON T.id = C.parent_id
)
SELECT EXP(sum(log(quantity)))
FROM myCTE
Demo SQL Fiddle
Multiplication method for values in a column, SELECT EXP(sum(log(quantity))), taken from here.
I need help building a query, which returns the Minimum difference between Value + another Value from same table and the other ID that gave the result (plus the sum can't be sum of the value itself)
Table:
ID Value
1 1
2 2
3 5
4 -10
5 -5
6 3
7 -15
Expected result:
ID Value MinDif IDofTheOtherValue
1 1 3 2 <-- MinDif = 1 + 2 (ID 1 + ID 2)
2 2 3 1 <-- MinDif = 2 + 1 (ID 2 + ID 1)
3 5 0 5 <-- MinDif = 5 + -5 (ID 3 + ID 5)
4 -10 -5 3 <-- MinDif = -10 + 5 (ID 4 + ID 3)
5 -5 0 3 <-- MinDif = -5 + 5 (ID 5 + ID 3)
6 3 -2 5 <-- MinDif = 3 + -5 (ID 6 + ID 5)
7 -15 -10 3 <-- MinDif = -15 + 5 (ID 7 + ID 3)
Here's a query to create the table:
DECLARE #myTable TABLE(ID int, Value int)
INSERT INTO #myTable VALUES (1, 1), (2,2), (3, 5), (4, -10), (5, -5), (6, 3), (7, -15)
And here's what I have tried, but this gives an SQL error (Cannot perform an aggregate function on an expression containing an aggregate or a subquery.)
SELECT m.ID, MIN(ABS(m.Value + (SELECT m2.Value FROM #myTable m2)))
FROM #myTable m
This is giving your required results:
with diffRank as
(
select ID = t1.ID
, minDif = t1.value + t2.value
, IDofTheOtherValue = t2.ID
, diffRank = row_number() over (partition by t1.ID order by abs(t1.value + t2.value), t2.ID)
from #myTable t1
inner join #myTable t2 on t1.ID <> t2.ID
)
select ID
, minDif
, IDofTheOtherValue
from diffRank
where diffRank = 1
order by ID;
SQL Fiddle with demo.
I resolved this by myself. Here's the Select clause:
SELECT tab.ID, tab.Value, test.*
FROM #myTable tab
OUTER APPLY
(SELECT TOP 1 ID AS [AnotherID], [SUM]
FROM
(
SELECT m.ID, m2.ID AS [ID2], m.Value + m2.Value AS [SUM]
FROM #myTable m
JOIN #myTable m2 ON m2.ID <> m.ID
) apu WHERE ID2 = tab.ID ORDER BY ABS([SUM])) test
In Oracle I would do:
select x.id, (select min(abs(x.value + y.value)) from my_table y),
(select first value (y.id) over (order by abs(x.value + y.value))
from my_table y)
from my_table x
think of something similar in TSQL
Try this.. it should work.
DECLARE #myTable TABLE(ID int, Value int)
INSERT INTO #myTable VALUES (1, 1), (2,2), (3, 5), (4, -10), (5, -5), (6, 3), (7, -15)
SELECT C.ID, C.Value
, C.Value + (SELECT TOP 1 E.Value FROM #myTable E WHERE C.AbsMinDif = ABS(C.Value + E.Value) ORDER BY E.ID) MinDif
, (SELECT TOP 1 F.ID FROM #myTable F WHERE C.AbsMinDif = ABS(C.Value + F.Value) ORDER BY F.ID) IDofTheOtherValue
FROM (
SELECT A.ID, MIN(A.Value) Value, MIN(ABS(A.Value + B.Value)) AbsMinDif
FROM #myTable A
CROSS JOIN #myTable B
WHERE A.ID <> B.ID
GROUP BY A.ID
) C