SQL Server 2008 - merge rows when condition matched - sql-server
I am running a stored procedure and getting the following value.
Name ID NewID Qty Rqty Total
Test1 1 5 4 9
Test2 10 1001 3 0 3
Test2 1001 4 2 6
Test3 15 1005 0 0 0
Test3 1005 3 4 7
If you look the Test3, where first id 15 has a new id 1005 But the Qty and Rqty is 0, next line I am getting ID 1005 and Qty, Rqty 3 and 4, total 7and this is correct.
What I am trying to do is when any ID got a new ID and Qty, Rqty both are 0, I need the following output in on row
Test3 15 1005 3 4 7
So, my final results will be -
Name ID NewID Qty Rqty Total
Test1 1 5 4 9
Test2 10 1001 3 0 3
Test2 1001 4 2 6
Test3 15 1005 3 4 7
My stored procedure is -
select Name, ID, NewID, Qty, RQty, SUM(Qty + RQty) as Total
from table1
Group By Name, ID, NewID, Qty, RQty
Order by Name
Could anyone help to solve this issue please.
Thanks
You will need to generate a psuedo "grouping" ID and NewID based on your conditions, group on those fields and select the MIN and MAX of the original ID and NewID along with aggregates of your other values. e.g.
CREATE TABLE dbo.Tests
(
Name varchar(10),
ID int,
[NewID] int NULL,
Qty int,
Rqty int
);
INSERT dbo.Tests (Name,ID,[NewID],Qty,Rqty)
--VALUES ('Test1',1,NULL,5,4)
-- ,('Test2',10,1001,3,0)
-- ,('Test2',1001,NULL,4,2)
-- ,('Test3',15,1005,0,0)
-- ,('Test3',1005,NULL,3,4);
VALUES ('test1',1,101,0,0)
,('test1',101,NULL,2,4)
,('test2',2,102,0,0)
,('test2',102,NULL,4,5)
,('test3',3,103,0,0)
,('test3',103,NULL,3,3)
,('test4',4,104,0,0)
,('test4',104,NULL,1,3)
,('test5',5,105,0,0)
,('test5',105,NULL,3,6);
SELECT t.Name,
min(t.ID) AS ID,
max(t.[NewID]) AS [NewID],
sum(t.Qty) AS Qty,
sum(t.Rqty) AS Rqty,
sum(t.Qty)+sum(t.Rqty) AS Total
FROM dbo.Tests AS t
CROSS APPLY (VALUES(CASE WHEN Qty = 0 AND Rqty = 0 AND t.[NewID] IS NOT NULL THEN [NewID] ELSE ID END,
CASE WHEN Qty = 0 AND Rqty = 0 AND t.[NewID] IS NOT NULL THEN -1 ELSE coalesce([NewID],-1) END)
) x(GroupingID, GroupingNewID)
GROUP BY Name,x.GroupingID,x.GroupingNewID
ORDER BY Name,max(t.ID);
Related
Count number of rows for each id to create a new column
ID value 1 4 1 5 3 4 2 10 I want to add another column called count, that has for each id the number of observations. Transformed table id value count 1 4 2 1 5 2 3 4 1 2 10 1
You can use the OVER() clause to aggregate. SELECT ID, value, [count] = COUNT(*) OVER (PARTITION BY ID) FROM dbo.TableName;
How to check values of different rows of a table
I have below sample input table. In real it has lots of records. Input: ID Classification 123 1 123 2 123 3 123 4 657 1 657 3 657 4 For a 'ID', I want it's records should have 'Classification' column contains all the values 1, 2, 3 and 4. If any of these values are not present then that ID's records should be considered as an exception. The output should be as below. ID Classification Flag 123 1 0 123 2 0 123 3 0 123 4 0 657 1 1 657 3 1 657 4 1 Can someone please help me with how can this can be achieved in sql server. Thanks.
There are a couple of options here, which is more performant is up to you to test, not me (especially when I don't know what indexes you have). One uses conditional aggregation, to check that all the values are there, and the other uses a subquery and counts the DISTINCT values (as I don't know if there could be duplicate classifications): SELECT * INTO dbo.YourTable FROM (VALUES(123,1), (123,2), (123,3), (123,4), (657,1), (657,3), (657,4))V(ID,Classification); GO CREATE CLUSTERED INDEX CI_YourIndex ON dbo.YourTable (ID,Classification); GO SELECT ID, Classification, CASE WHEN COUNT(CASE YT.Classification WHEN 1 THEN 1 END) OVER (PARTITION BY ID) > 0 AND COUNT(CASE YT.Classification WHEN 2 THEN 1 END) OVER (PARTITION BY ID) > 0 AND COUNT(CASE YT.Classification WHEN 3 THEN 1 END) OVER (PARTITION BY ID) > 0 AND COUNT(CASE YT.Classification WHEN 4 THEN 1 END) OVER (PARTITION BY ID) > 0 THEN 1 ELSE 0 END AS Flag FROM dbo.YourTable YT; GO SELECT ID, Classification, CASE (SELECT COUNT(DISTINCT sq.Classification) FROM dbo.YourTable sq WHERE sq.ID = YT.ID AND sq.Classification IN (1,2,3,4)) WHEN 4 THEN 1 ELSE 0 END AS Flag FROM dbo.YourTable YT; GO DROP TABLE dbo.YourTable;
Get top X percentage based on cumulative sum
My table looks like this: ID | ItemID | ItemQualityID | Amount | UnitPrice My goal is to find the top x% rows for each ItemID + ItemQualityID pair based on Amount cumulative sum and ordered by UnitPrice. For example: ID | ItemID | ItemQualityID | Amount | UnitPrice 1 1 1 18 2 2 1 1 1 1 3 1 1 1 1 4 2 1 18 2 5 2 1 1 1 6 2 1 1 1 7 1 1 1 3 and I want the top 10%, then the resulting table should contain row #2, 3, 5, 6. Since the total amount for ItemID 1 and 2 are 21 and 20 respectively, thus 10% would be 2 items each. If I want the top 20%, the resulting table should still be the same since if I include row 1 and 4 it would make it 100%. Row #7 has unit price > row #1 so if row #1 is not included then row #7 shouldn't be included as well. Ideally I want the table with all the filtered rows for some other calculations but I will be happy even if I can only get the sum of Amount * UnitPrice of the filtered table. Something like ItemID | ItemQualityID | Sum 1 1 2 2 1 2 for the above example.
You can use SUM OVER : DECLARE #percent DECIMAL(5, 2) = .1 ;WITH CteSum AS( SELECT *, TotalSum = SUM(Amount) OVER(PARTITION BY ItemID, ItemQualityID), CumSum = SUM(Amount) OVER(PARTITION BY ItemID, ItemQualityID ORDER BY UnitPrice, ID) FROM tbl ) SELECT ItemID, ItemQualityID, [Sum] = SUM(Amount * UnitPrice) FROM CteSum WHERE CumSum <= #percent * TotalSum GROUP BY ItemID, ItemQualityID ONLINE DEMO
Sql Server query is not giving proper result
I have table SentNewsletters. This table has following columns. 1. ID 2. Surah_no 3. Aayt 4. Sent_date, 5. Sent_By I want to select id ,surah_no ,aayt ,sent_date (MAx) Sent_by, Surah_no and Aayt have multiple records like Id ID Surah_no aayt sent_date Sent_By 1 1 1 2013-04-08 19:39:26.127 Test 2 1 1 2013-04-08 20:03:24.920 Test 3 1 1 2013-04-08 19:39:26.127 Test 4 1 1 2013-04-08 20:03:24.920 Test 5 1 1 2013-04-08 20:19:26.033 User3 6 1 1 2013-04-08 20:24:47.890 User3 select Count(*) ,surano ,Aaytno ,MAx(SENT_DATE) from sentnewsletters group by SuraNo ,Aaytno I need Id and Sent_By also select Count(*) ID ,surano ,Aaytno ,MAx(SENT_DATE) , Sent_by from sentnewsletters group by SuraNo ,Aaytno
You could use... select Count(*) as Count ,surano ,Aaytno ,MAx(SENT_DATE) as SentDate , Sent_by from sentnewsletters group by SuraNo ,Aaytno ,Sent_by You can't group on the ID since each record is different, you will essentially have the same result as just querying the table with... select 1 as Count ,surano ,Aaytno ,SENT_DATE, Sent_by from sentnewsletters The result woudl look like.. Count Surah_no aayt sent_date Sent_By 4 1 1 2013-04-08 20:03:24.920 Test 2 1 1 2013-04-08 20:24:47.890 User3
How to assign an alternating row number based on a table primary key?
I have a table with data named Product ProductID ProductName 1 ABC 2 PQR 3 XYZ 4 HJK 5 LKJ 6 MNB ... .... with many more product in it. What I want is result like this on Select query: RowNo ProductID ProductName 1 1 ABC 1 2 PQR 2 3 XYZ 2 4 HJK 1 5 LKJ 1 6 MNB 2 7 klj 2 8 hjg then 1,1, 2,2 1,1 for the number of records in the table. Is it possible, and if so how can I do that?
This works for your sample data which assumes ProductID is contiguous: SELECT CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END, ProductID, ProductName FROM Product Now, guessing that you mean in resultset which may have gaps in ProductID SELECT CASE WHEN ContiguousProductID % 4 = 0 OR (ContiguousProductID+1) % 4 = 0 THEN 2 ELSE 1 END, --ContiguousProductID, --CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END, ProductID, ProductName FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS ContiguousProductID, ProductName, ProductID FROM dbo.Product ) P2