How to merge two row and sum some columns in an UPDATE? - sql-server

I work with SQL Server and I need to merge multiples rows only if they have the same value between them in two specific columns (Col_01 and Col_02 in my example).
When I merge them I have to sum some columns (Col_03 and Col_04 in my example).
I think an example will be the more explicit. Here is my table simplified :
| ID | Col_01 | Col_02 | Col_03 | Col_04 |
| 1 | ABC | DEF | 2 | 2 |
| 2 | ABC | DEF | 1 | 0 |
| 3 | DEF | GHI | 0 | 2 |
| 4 | ABC | GHI | 1 | 0 |
| 5 | JKL | GHI | 0 | 2 |
And here is what I want after my update :
| ID | Col_01 | Col_02 | Col_03 | Col_04 |
| 2 | ABC | DEF | 3 | 2 |
| 3 | DEF | GHI | 0 | 2 |
| 4 | ABC | GHI | 1 | 0 |
| 5 | JKL | GHI | 0 | 2 |
I merged ID 1 and ID 2 because they had the same Col_01 and the same Col_02.
I tried a query like that
SELECT MAX(ID), Col_01, Col_02, SUM(Col_03), SUM(Col_04)
FROM Table
GROUP BY Col_01, Col_02
I've got what the rows merged but I loose the not merged ones.
I don't know how to properly use it in an UPDATE query in order to merge the rows with the same (Col_01, Col_02) and keep the others. Can you help me to do this ?

So you actually need to delete some rows from original table. Use MERGE statement for that:
MERGE Table tgt
USING (SELECT MAX(ID) as ID, Col_01, Col_02, SUM(Col_03) AS Col_03, SUM(Col_04) AS Col_04
FROM Table
GROUP BY Col_01, Col_02) src ON tgt.ID = srs.ID
WHEN MATCHED THEN
UPDATE
SET Col_03 = src.Col_03, Col_04 = src.Col_04
WHEN NOT MATCHED BY SOURCE THEN
DELETE

Try this:
UPDATE T SET
T.Col_03 = G.Col_03,
T.Col_04 = G.Col_04
FROM Table AS T INNER JOIN
(SELECT MAX(ID) AS ID, Col_01, Col_02, SUM(Col_03) AS Col_03, SUM(Col_04) AS Col_04
FROM Table
GROUP BY Col_01, Col_02) AS G
ON G.ID = T.ID

Related

Pivoting Data in SQL and Updting it into Destination Table

I am working on a Store Procedure where I need to update records from from table 1 into table 2.
Table1: contains the following 4 columns
----------------------------------------------
| ID | TableName | ColumnName | Value |
----------------------------------------------
| 1 | [UserDetails] | [FinalScore] | 92 |
| 2 | [UserDetails] | [FinalScore] | 89 |
| 3 | [UserDetails] | [FinalScore] | 65 |
| 4 | [UserDetails] | [FinalScore] | 91 |
| 5 | [UserDetails] | [FinalScore] | 76 |
| 1 |[EmployeeDetail]| [ScoreData] | 0.91 |
----------------------------------------------
UserDetails table
-----------------------------------------------------------
| UserID | UserName | ContactNo | FinalScore |
-----------------------------------------------------------
| 1 | John G | +13288992342 | 0 |
| 2 | Leonard J | +14581232342 | 0 |
| 3 | Max R | +17123992342 | 0 |
| 4 | Robert H | +15688992122 | 0 |
| 5 | Jimmy L | +1328996782 | 0 |
-----------------------------------------------------------
Need to load all the data from table1 into the corresponding destination table for large amount of data (30,000 to 60,000) records.
Table1 contains the ID (from ID Column in table1) and FinalScore (from ColumnName Column in table1) in the destination table (from TableName Column in table1) where the value (from Value Column in table1) needs to be loaded.
End Result of UserDetails table after SP execution :
-----------------------------------------------------------
| UserID | UserName | ContactNo | FinalScore |
-----------------------------------------------------------
| 1 | John G | +13288992342 | 92 |
| 2 | Leonard J | +14581232342 | 89 |
| 3 | Max R | +17123992342 | 65 |
| 4 | Robert H | +15688992122 | 91 |
| 5 | Jimmy L | +1328996782 | 76 |
-----------------------------------------------------------
I am not sure how to load the data from "table1" into destination table (userdetails table) for bulk data as update query in a loop is taking very long time to complete.
It's not pivot what you're after but a simple join:
select
a.userid, a.contactno, b.finalscore
from UserDetails a
join table1 b on a.id = b.id
alternatively, if you want to update the old table without creating a new one, you can update join
SQL update query using joins

Sorting Table in hierarchical order

Is it possible to sorting queries table in hierarchical order like this:
Expected
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| ID | Code | Name | Qty | Amount | is_parent | parent_id | remarks |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 1 | ABC | Parent1 | 2 | 1,000 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 4 | FFLK | Product Z | 10 | 2,500 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 5 | P6DT | Product 5 | 7 | 1,700 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 6 | P2GL | Product T | 5 | 1,100 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 2 | DHG | Parent2 | 5 | 1,500 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 3 | LMSJ | Product U | 4 | 600 | 0 | 2 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
This is the original data table:
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| ID | Code | Name | Qty | Amount | is_parent | parent_id | remarks |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 1 | ABC | Parent1 | 2 | 1,000 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 2 | DHG | Parent2 | 5 | 1,500 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 3 | LMSJ | Product U | 4 | 600 | 0 | 2 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 4 | FFLK | Product Z | 10 | 2,500 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 5 | P6DT | Product 5 | 7 | 1,700 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 6 | P2GL | Product T | 5 | 1,100 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
is_parent column = 1 if data row set to parent, 0 if data row set to child
parent_id column = 0 if data row set to parent, depend on ID of parent data
I'm using SQL Server to generate the data.
It looks like the actual question is how to query the data in hierarchical order. This is possible using recursive queries but a faster alternative is to use SQL Server's support for hierarchical data.
A recursive query that returns the data in hierarchical order would look like this :
WITH h AS
(
SELECT
ID,Code,Name,Qty,Amount,is_parent,parent_id,remarks
FROM
dbo.ThatTable
WHERE
parent_id=0
UNION ALL
SELECT
c.ID,c.Code,c.Name,c.Qty,c.Amount,c.is_parent,c.parent_id,c.remarks
FROM
dbo.ThatTable c
INNER JOIN h ON
c.parent_id= h.Id
)
SELECT * FROM h
This query's performance will be acceptable if the ID and Parent_ID fields are indexed, but not great.
Adding a hierarchyid field to the table would make the query simpler and far faster. Assuming there's a hierarchy field, the query would be just :
SELECT *
FROM ThatTable
ORDER BY hierarchy
Adding an index on hierarchy will this query and any query that looks eg for children of a specific node, very fast. Instead of querying recursively, the server only needs to look into that single index.
The article Lesson 1: Converting a Table to a Hierarchical Structure shows how to create a new table with a hierarchyid and populate it from parent/child data.

SQL SELECT and INSERT/UPDATE, PIVOT?

I need to take data from a table that looks like this:
name | server | instance | version | user
----------|----------|------------|----------|--------- -
package_a | x | 1 | 1 | AB
package_b | x | 1 | 1 | TL
package_a | x | 2 | 4 | SK
package_a | y | 1 | 2 | MD
package_c | y | 1 | 4 | SK
package_b | y | 2 | 1 | SK
package_a | y | 2 | 1 | TL
package_b | x | 2 | 3 | TL
package_c | x | 2 | 1 | TL
and I need to put it in a table like that:
name | v_x_1 | u_x_1 | v_x_2 | u_x_2 | v_y_1 | u_y_1 | v_y_2 | u_y_2
----------|-------|-------|-------|-------|-------|-------|-------|-------
package_a | 1 | AB | 4 | SK | 2 | MD | 1 | TL
package_b | 1 | TL | 3 | TL | NULL | NULL | 1 | SK
package_c | NULL | NULL | 1 | TL | 4 | SK | NULL | NULL
I already tried INSERT with (SUB)SELECT, tried to INSERT package names first using DISTINCT and UPDATE afterwards, played around with PIVOT and stuff like that.
But I'm rather new to SQL and programming in general, so I couldn't come up with a solution. Since I not only have a version number in the source table but also nvarchar columns, It seems like PIVOT won't be the way to go, right?
You can use PIVOT on a sub query that uses UNION to separate the user and version values.
insert into YourNewTable (name, [v_x_1],[u_x_1],[v_x_2],[u_x_2],[v_y_1],[u_y_1],[v_y_2],[u_y_2])
select *
from (
select name, cast([version] as varchar(30)) as value, concat('v_',[server],'_',instance) as title from YourTable
union all
select name, [user] as value, concat('u_',[server],'_',instance) as title from YourTable
) q
pivot (max(value) FOR title IN (
[v_x_1],[u_x_1],[v_x_2],[u_x_2],[v_y_1],[u_y_1],[v_y_2],[u_y_2]
)
) pvt;

How to create a cross tab (in crystal) from multiple columns (in sql)

I have 5 columns in SQL that I need to turn into a cross tab in Crystal.
This is what I have:
Key | RELATIONSHIP | DISABLED | LIMITED | RURAL | IMMIGRANT
-----------------------------------------------------------------
1 | Other Dependent | Yes | No | No | No
2 | Victim/Survivor | No | No | No | No
3 | Victim/Survivor | Yes | No | No | No
4 | Child | No | No | No | No
5 | Victim/Survivor | No | No | No | No
6 | Victim/Survivor | No | No | No | No
7 | Child | No | No | No | No
8 | Victim/Survivor | No | Yes | Yes | Yes
9 | Child | No | Yes | Yes | Yes
10 | Child | No | Yes | Yes | Yes
This is what I want the cross tab to look like (Distinct count on Key):
| Victim/Survivor | Child | Other Dependent | Total |
--------------------------------------------------------------
| DISABLED | 1 | 0 | 1 | 2 |
--------------------------------------------------------------
| LIMITED | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| RURAL | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| IMMIGRANT | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| TOTAL | 4 | 6 | 1 | 11 |
--------------------------------------------------------------
I used this formula in Crystal in an effort to combine 4 columns (Field name = {#OTHERDEMO})...
IF {TABLE.DISABLED} = "YES" THEN "DISABLED" ELSE
IF {TABLE.LIMITED} = "YES" THEN "LIMITED" ELSE
IF {TABLE.IMMIGRANT} = "YES" THEN "IMMIGRANT" ELSE
IF {TABLE.RURAL} = "YES" THEN "RURAL"
...then made the cross-tab with #OTHERDEMO as the rows, RELATIONSHIP as the Columns with a distinct count on KEY:
Problem is, once crystal hits the first "Yes" it stops counting thus not categorizing correctly in the cross-tab. So I get a table that counts the DISABILITY first and gives the correct display, then counts the Limited and gives some info, but then dumps everything else.
In the past, I have done mutiple conditional formulas...
IF {TABLE.DISABLED} = "YES" AND {TABLE.RELATIONSHIP} = "Victim/Survivor" THEN {TABLE.KEY} ELSE {#NULL}
(the #null formula is because Crystal, notoriously, gets confused with nulls.)
...then did a distinct count on Key, and finally summed it in the footer.
I am convinced there is another way to do this. Any help/ideas would be greatly appreciated.
If you unpivot those "DEMO" columns into rows it will make the crosstab super easy...
select
u.[Key],
u.[RELATIONSHIP],
u.[DEMO]
from
Table1
unpivot (
[b] for [DEMO] in ([DISABLED], [LIMITED], [RURAL], [IMMIGRANT])
) u
where
u.[b] = 'Yes'
SqlFiddle
or if you were stuck on SQL2000 compatibility level you could manually unpivot the Yes values...
select [Key], [REALTIONSHIP], [DEMO] = cast('DISABLED' as varchar(20))
from Table1
where [DISABLED] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('LIMITED' as varchar(20))
from Table1
where [LIMITED] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('RURAL' as varchar(20))
from Table1
where [RURAL] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('IMMIGRANT' as varchar(20))
from Table1
where [IMMIGRANT] = 'Yes'
For the crosstab, use a count on the Key column (aka row count), [DEMO] on rows, and [RELATIONSHIP] on columns.

records exist or not based on conditions in sql server 2008

Hi I have doubt in sql server
Trantable:
empid | deptid | Projectname | Transactionid
1 |10 | test | 1
2 |11 | test1 | 2
2 |10 | jai | 3
2nd table: dimemp ....> here dimemp is scdtype2 dimension.its all ready done
empkey | empid | ename | flag
1 | 1 | a | 1
2 | 2 | b | 1
3 | -1 | na | 1
3rd table: dimdept------>here dimdept is scdtype2 dimension.implementaion allready done.
deptkey | deptid | deptname | flag
1 | 10 | hr | 1
2 | 11 | ceo | 1
3 | -1 | NA | 1
Here I want load trantable data into facttran table with corresponding keys. here transactionid is unique column
to identiy unique record.
Facttran table structure look like below and factran we need to maintain scd type1 data.
empkey | deptkey | projectname |transactionid
I tried like below query
merge into facttran target
using (select ISNULL(a.empkey, (select empkey from Dimemp where empid = -1)) empkey,ISNULL(b.deptkey, (select deptkey from dimdept where deptid = -1)) deptkey, c.projectname, c.transactionid
from trantable c
left join dimemp a on a.empid=c.empid and a.flag=1
left join dimdept b on b.deptid=c.deptid and b.flag=1)source
on target.transactionid=source.transactionid
when not matched
then insert ([deptkey],[empkey],[projectname],[transactionid])
values(source.deptkey,source.empkey,source.projectname,source.transactionid)
when matched
then update set target.empkey=source.empkey ,
target.deptkey=source.deptkey,
target.projectname=source.projectname,
target.transactionid=source.transactionid ;
then I got output like below
Table :facttran
empkey | deptkey | projectname |transactionid
1 | 1 | test | 1
2 | 2 | test1 | 2
2 | 1 | Jai | 3
upto now its working fine.
2nd day in my trantable few records updated and few records insert in sourc trantable.based on below table data I want update in facttable with corresponding key.
2nd table: dimemp ....> here dimemp is scdtype2 dimension
empkey | empid | ename | flag
1 | 10 | a | 0
2 | 11 | b | 1
3 | -1 | na | 1
4 | 10 | aaa | 1
3rd table: dimdept------>here dimdept is scdtype2 dimension.implementaion allready done.
deptkey | deptid | deptname | flag
1 | 10 | hr | 0
2 | 20 | ceo | 1
3 | -1 | NA | 1
4 | 10 |hrdept | 1
Trantable:
empid | deptid | Projectname | Transactionid
1 |11 | test | 1 ------record updated in source side here deptid changed from 10 to 11
1 |11 | test123 | 2 -------Here empid changed from empid 2 to 1 and projectname changed test1 to test123
2 |10 | jai | 3 ------here no records are not changed
1 |10 | cod | 4 ----------new rocrd is came
based on above trantable.I want facttran table data look like below.
Table :facttran
empkey | deptkey | projectname |transactionid
1 | 2 | test | 1
1 | 2 | test123 | 2
2 | 1 | Jai | 3
4 | 10 | cod | 4
when I ran 2nd time with same query.I am not able get to expected result.
here mainily source trantable related transactioni id is exist or not in facttran table .if not exist then we need to insert correspondig dimensionkeys with lates flaf=1
values.if we found transactionid exist in fact table then we need to updated existing dimension corresonding key.
suppose if we take transactionid=1 records here only chnaged deptid not empid that time we donot need update empid corresponding lates flag=1 corresondingkey
we need check exisig transaction id is updated each dimension need to check exist or not if not exist latest flag=1 related corresponding key.
if exist we donot need to updated that one.if new reocrds came then we need to insert with latest flag=1 corresponding keys in factran table.
please tell me how to write query to achive this task in sql server.

Resources