Wrong calculation in Sum() - sql

hi i have 2 table and i want plus it.
Table 1 --> StudentId = 1 ,Score = 10 , 20 ,30 , StudentId = 2 ,Score = 5, 5
Table 2 --> StudentId = 1 ,Score = 5, 10 ,15 , StudentId = 2 ,Score = 15, 25
Total = StudentId = 1 ---> 90 , StudentId = 2 ---> 45
i use this query:
Select Sum(tbl_EvaPoint.Score + tbl_ActPoint.Score ),
tbl_ActPoint.StudentId
From tbl_EvaPoint
JOIN tbl_ActPoint
ON tbl_EvaPoint.StudentId = tbl_ActPoint.StudentId
GROUP BY tbl_ActPoint.StudentId`
everythings is ok but i get wrong sum instead of 90 and 45 i get 180 and 90 or somthings else.

Use UNION instead of JOIN
SELECT student_id, SUM(score)
FROM (SELECT student_id, score FROM Table1
UNION ALL
SELECT student_id, score FROM Table2
) as T
GROUP BY student_id

I think a CTE is more readable, but that is personal preference.
CREATE TABLE #S1 (
StudentID smallint
,Score smallint )
INSERT INTO #S1
SELECT 1, 10;
INSERT INTO #S1
SELECT 1, 20;
INSERT INTO #S1
SELECT 1, 30;
INSERT INTO #S1
SELECT 2, 5
INSERT INTO #S1
SELECT 2, 5;
CREATE TABLE #S2 (
StudentID smallint
,Score smallint )
INSERT INTO #S2
SELECT 1, 5;
INSERT INTO #S2
SELECT 1, 10;
INSERT INTO #S2
SELECT 1, 15;
INSERT INTO #S2
SELECT 2, 15;
INSERT INTO #S2
SELECT 2, 25;
WITH CTE AS (
SELECT
StudentID, Score
FROM #S1
UNION ALL
SELECT
StudentID, Score
FROM #S2 )
SELECT
StudentID
,SUM(Score) AS TotalScore
FROM CTE
GROUP BY StudentID

Related

SQL: Pinned rows and row number calculation

We have a requirement to assign row number to all rows using following rule
Row if pinned should have same row number
Otherwise sort it by GMD
Example:
ID GMD IsPinned
1 2.5 0
2 0 1
3 2 0
4 4 1
5 3 0
Should Output
ID GMD IsPinned RowNo
5 3 0 1
2 0 1 2
1 2.5 0 3
4 4 1 4
3 2 0 5
Please Note row number for Id's 2 and 4 stayed intact as they are pinned with values of 2 and 4 respectively even though the GMD are not in any order
Rest of rows Id's 1, 3 and 5 row numbers are sorted using GMD desc
I tried using RowNumber SQL 2012 however, it is pushing pinned items from their position
Here's a set-based approach to solving this. Note that the first CTE is unnecessary if you already have a Numbers table in your database:
declare #t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into #t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from #t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from #t where IsPinned=1)
), DataWithout as (
select
*,
ROW_NUMBER() OVER (ORDER BY GMD desc) as rn
from
#t
where
IsPinned = 0
)
select
t.*,
COALESCE(nw.n,t.ID) as RowNo
from
#t t
left join
DataWithout dw
inner join
NumbersWithout nw
on
dw.rn = nw.rn
on
dw.ID = t.ID
order by COALESCE(nw.n,t.ID)
Hopefully my naming makes it clear what we're doing. I'm a bit cheeky in the final SELECT by using a COALESCE to get the final RowNo when you might have expected a CASE expression. But it works because the contents of the DataWithout CTE is defined to only exist for unpinned items which makes the final LEFT JOIN fail.
Results:
ID GMD IsPinned RowNo
----------- --------------------------------------- -------- --------------------
5 3.00 0 1
2 0.00 1 2
1 2.50 0 3
4 4.00 1 4
3 2.00 0 5
Second variant that may perform better (but never assume, always test):
declare #t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into #t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from #t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from #t where IsPinned=1)
), DataPartitioned as (
select
*,
ROW_NUMBER() OVER (PARTITION BY IsPinned ORDER BY GMD desc) as rn
from
#t
)
select
dp.ID,dp.GMD,dp.IsPinned,
CASE WHEN IsPinned = 1 THEN ID ELSE nw.n END as RowNo
from
DataPartitioned dp
left join
NumbersWithout nw
on
dp.rn = nw.rn
order by RowNo
In the third CTE, by introducing the PARTITION BY and removing the WHERE clause we ensure we have all rows of data so we don't need to re-join to the original table in the final result in this variant.
this will work:
CREATE TABLE Table1
("ID" int, "GMD" number, "IsPinned" int)
;
INSERT ALL
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (1, 2.5, 0)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (2, 0, 1)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (3, 2, 0)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (4, 4, 1)
INTO Table1 ("ID", "GMD", "IsPinned")
VALUES (5, 3, 0)
SELECT * FROM dual
;
select * from (select "ID","GMD","IsPinned",rank from(select m.*,rank()over(order by
"ID" asc) rank from Table1 m where "IsPinned"=1)
union
(select "ID","GMD","IsPinned",rank from (select t.*,rank() over(order by "GMD"
desc)-1 rank from (SELECT * FROM Table1)t)
where "IsPinned"=0) order by "GMD" desc) order by rank ,GMD;
output:
2 0 1 1
5 3 0 1
1 2.5 0 2
4 4 1 2
3 2 0 3
Can you try this query
CREATE TABLE Table1
(ID int, GMD numeric (18,2), IsPinned int);
INSERT INTO Table1 (ID,GMD, IsPinned)
VALUES (1, 2.5, 0),
(2, 0, 1),
(3, 2, 0),
(4, 4, 1),
(5, 3, 0)
select *, row_number () over(partition by IsPinned order by (case when IsPinned =0 then GMD else id end) ) [CustOrder] from Table1
This took longer then I thought, the thing is row_number would take a part to resolve the query. We need to differentiate the row_numbers by id first and then we can apply the while loop or cursor or any iteration, in our case we will just use the while loop.
dbo.test (you can replace test with your table name)
1 2.5 False
2 0 True
3 3 False
4 4 True
6 2 False
Here is the query I wrote to achieve your result, I have added comment under each operation you should get it, if you have any difficultly let me know.
Query:
--user data table
DECLARE #userData TABLE
(
id INT NOT NULL,
gmd FLOAT NOT NULL,
ispinned BIT NOT NULL,
rownumber INT NOT NULL
);
--final result table
DECLARE #finalResult TABLE
(
id INT NOT NULL,
gmd FLOAT NOT NULL,
ispinned BIT NOT NULL,
newrownumber INT NOT NULL
);
--inserting to uer data table from the table test
INSERT INTO #userData
SELECT t.*,
Row_number()
OVER (
ORDER BY t.id ASC) AS RowNumber
FROM test t
--creating new table for ids of not pinned
CREATE TABLE #ids
(
rn INT,
id INT,
gmd FLOAT
)
-- inserting into temp table named and adding gmd by desc
INSERT INTO #ids
(rn,
id,
gmd)
SELECT DISTINCT Row_number()
OVER(
ORDER BY gmd DESC) AS rn,
id,
gmd
FROM #userData
WHERE ispinned = 0
--declaring the variable to loop through all the no pinned items
DECLARE #id INT
DECLARE #totalrows INT = (SELECT Count(*)
FROM #ids)
DECLARE #currentrow INT = 1
DECLARE #assigningNumber INT = 1
--inerting pinned items first
INSERT INTO #finalResult
SELECT ud.id,
ud.gmd,
ud.ispinned,
ud.rownumber
FROM #userData ud
WHERE ispinned = 1
--looping through all the rows till all non-pinned items finished
WHILE #currentrow <= #totalrows
BEGIN
--skipping pinned numers for the rows
WHILE EXISTS(SELECT 1
FROM #finalResult
WHERE newrownumber = #assigningNumber
AND ispinned = 1)
BEGIN
SET #assigningNumber = #assigningNumber + 1
END
--getting row by the number
SET #id = (SELECT id
FROM #ids
WHERE rn = #currentrow)
--inserting the non-pinned item with new row number into the final result
INSERT INTO #finalResult
SELECT ud.id,
ud.gmd,
ud.ispinned,
#assigningNumber
FROM #userData ud
WHERE id = #id
--going to next row
SET #currentrow = #currentrow + 1
SET #assigningNumber = #assigningNumber + 1
END
--getting final result
SELECT *
FROM #finalResult
ORDER BY newrownumber ASC
--dropping table
DROP TABLE #ids
Output:

Get the id of the last record in the data SQL Server

I am trying to get the last ID from at least 4 child-parent relationships between ID's and sum all related ID's quantity. I have tried below -
declare #test table (ID int not null, P_ID int null, Qty int not null)
insert into #test(ID, P_ID, Qty) values
(1 , 11 , 1),
(2 , null, 3),
(11, 21 , 2),
(21, 31 , 1),
(31, null, 3),
(12, null, 4)
select
COALESCE(T2.ID,T1.ID) as ID,
MAX(CASE WHEN T1.P_ID is not null then T1.ID END) as OldID,
SUM(Qty) as Qty
from
#test T1
left join
(select ID from #test
GROUP By ID) T2
on T2.ID = T1.P_ID
group by
COALESCE(T2.ID, T1.ID)
I am getting output -
ID OldID Qty
2 NULL 3
11 1 1
12 NULL 4
21 11 1
31 21 2
But I want my output will be like this where all ID's with no Parent ID in the first row then all previous ID's will show and SUM all relevant ID's quantity -
ID OldID3 OldID2 OldID1 Qty
2 3
12 4
31 21 11 1 7
Could someone please help me to achieve this.
Thanks in advance
Hopefully, this helps you. I have not tested it thoroughly, so apologies for any bugs.
I'm using a Common Table Expression to get the hierarchy information, then using a dynamic SQL I extract the desired number of previous IDs.
DECLARE #test TABLE (ID INT NOT NULL, P_ID INT NULL, Qty INT NOT NULL);
INSERT INTO #test(ID, P_ID, Qty) VALUES
(1 , 11 , 1),
(2 , null, 3),
(11, 21 , 2),
(21, 31 , 1),
(31, null, 3),
(12, null, 4);
IF (OBJECT_ID('tempdb..#hierarchy') IS NOT NULL)
DROP TABLE #hierarchy;
CREATE TABLE #hierarchy (
RootID INT NOT NULL, ID INT NOT NULL, [Qty] INT NOT NULL, SeqIndex INT NOT NULL
);
;WITH hierarchy AS (
SELECT ID, P_ID, Qty, ID [RootID], 0 [SeqIndex]
FROM #test
WHERE P_ID IS NULL
UNION ALL
SELECT child.ID, child.P_ID, child.Qty, parent.RootID, parent.SeqIndex + 1 [SeqIndex]
FROM #test child
JOIN hierarchy parent ON parent.ID=child.P_ID
)
INSERT #hierarchy
SELECT RootID, ID, Qty, SeqIndex
FROM hierarchy;
DECLARE
#DEPTH INT = 3,
#maxSeqIndex INT = (SELECT MAX(SeqIndex) FROM #hierarchy);
IF (#DEPTH = 0)
SELECT RootID, SUM(Qty) [Qty]
FROM #hierarchy
GROUP BY RootID;
ELSE IF (#DEPTH > #maxSeqIndex)
SELECT NULL
ELSE BEGIN
DECLARE #SQL NVARCHAR(MAX) = N'
SELECT
RootID,
';
DECLARE #idx INT = 1;
WHILE #idx <= #DEPTH BEGIN
SET #SQL += N'
(SELECT ID FROM #hierarchy i WHERE i.RootID=o.RootID AND SeqIndex='+CAST(#idx as nvarchar(10))+N') [OldID'+CAST(#maxSeqIndex-#idx+1 as nvarchar(10))+N'],';
SET #idx += 1;
END
SET #SQL += N'
SUM(Qty) [Qty]
FROM #hierarchy o
GROUP BY RootID;';
EXEC sp_executesql #SQL
END
Of course, the dynamic script could be replaced with a hard-coded SQL if that is OK for you.
Note: performance has not been considered

How to get anchor details when using CTE?

I have a table with 2 columns (id, childId) with the following data:
1, 2
2, 4
3, 5
4, 6
5, null
6, null
I have the following CTE that gets the records and it works fine.
DECLARE #id TABLE (id int, childId int);
INSERT INTO #id SELECT 1, 2;
INSERT INTO #id SELECT 2, 4;
INSERT INTO #id SELECT 3, 5;
INSERT INTO #id SELECT 4, 6;
INSERT INTO #id SELECT 5, null;
INSERT INTO #id SELECT 6, null;
WITH cte AS
(
SELECT id, childId
FROM #id
WHERE id = 1
UNION ALL
SELECT b.id, b.childId
FROM #id b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
However, I would like to add the anchor details so that the results will look like:
1, 2, null
2, 4, 1
4, 6, 1
6, null, 1
So that that 3rd column is the main anchor record.
Is this possible?
Just add a thrid column in CTE.
declare #mytable table ( id int, childId int );
insert #mytable
( id, childId )
values ( 1, 2 ),
( 2, 4 ),
( 3, 5 ),
( 4, 6 ),
( 5, null ),
( 6, null );
declare #id table ( id int );
insert into #id
select 1;
insert into #id
select 3;
with cte
as ( select id ,
childId ,
id root
from #mytable
where id in ( select id
from #id )
union all
select b.id ,
b.childId ,
cte.root
from #mytable b
inner join cte on b.id = cte.childId
)
select *
from cte;
WITH cte AS
(
SELECT id, childId, id AS anchorId
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT b.id, b.childId, cte.anchorId
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT
id
, childId
, case
WHEN id = anchorId THEN NULL
ELSE anchorId
END as anchorId
FROM cte
With test code provided:
DECLARE #id TABLE (id int, childId int);
INSERT INTO #id SELECT 1, 2;
INSERT INTO #id SELECT 2, 4;
INSERT INTO #id SELECT 3, 5;
INSERT INTO #id SELECT 4, 6;
INSERT INTO #id SELECT 5, null;
INSERT INTO #id SELECT 6, null;
WITH cte AS
(
SELECT id, childId, id AS anchorId
FROM #id
WHERE id IN (1,3)
UNION ALL
SELECT b.id, b.childId, cte.anchorId
FROM #id b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT
id
, childId
, CASE
WHEN id = anchorId THEN NULL
ELSE anchorId
END AS anchorId
FROM cte

SQL Query-Group by and filters

I have the table as shown in below image.
I am trying to get the latest status_id, grouped by team_id and based on max of created_date.
--Latest status for each team based on created date
SELECT *
FROM ProductionHistory
WHERE created_Date IN (
SELECT MAX(created_Date)
FROM ProductionHistory
GROUP BY TeamID
)
That's fine, here is the result:
My questions are:
How to ignore the assigned_to null then find latest record for team?
When there is only one record with assigned_to null for team, let's consider that.
For example: for Team_id 5 there is only one record with assigned_to null, we don't have any other record for team_id 5 with assigned_to set some value.
So we have consider this.
For team id 3 query result should ignore the record 4 (though max date), query result should contain record 2.
Here is the final result I am expecting:
Try this:
DECLARE #t TABLE
(
TicketID INT ,
TeamID INT ,
StatusID INT ,
created_Date DATETIME ,
Assigned_to NVARCHAR(MAX)
)
INSERT #t
VALUES ( 10000, 2, 7, '2015-03-26 01:48:00.000', 'W3ER45' ),
( 10000, 3, 7, '2015-03-26 05:48:00.000', 'YU67IO' ),
( 10000, 2, 9, '2015-03-26 03:48:00.000', 'HJKO98' ),
( 10000, 3, 9, '2015-03-27 03:48:00.000', NULL ),
( 10000, 4, 11, '2015-03-23 03:48:00.000', 'GHR67' ),
( 10000, 5, 11, '2015-03-27 02:12:56.910', NULL );
;
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY TicketID, TeamID ORDER BY CASE
WHEN Assigned_to IS NULL
THEN 1
ELSE 0
END, created_Date DESC ) AS rn
FROM #t
)
SELECT TicketID ,
TeamID ,
StatusID ,
created_Date ,
Assigned_to
FROM cte
WHERE rn = 1
Output:
TicketID TeamID StatusID created_Date Assigned_to
10000 2 9 2015-03-26 03:48:00.000 HJKO98
10000 3 7 2015-03-26 05:48:00.000 YU67IO
10000 4 11 2015-03-23 03:48:00.000 GHR67
10000 5 11 2015-03-27 02:12:56.910 NULL
Try this answer.I did it with cursor
DECLARE #t TABLE ( TicketID INT
, TeamID INT
, StatusID INT
, created_Date DATETIME
, Assigned_to NVARCHAR(MAX) )
DECLARE cur CURSOR READ_ONLY FAST_FORWARD
FOR SELECT [TeamID]
FROM TT
DECLARE #i int
OPEN cur
FETCH NEXT FROM cur INTO #i
WHILE ##FETCH_STATUS=0
BEGIN
IF (SELECT COUNT_BIG([TeamID])
FROM TT
WHERE [TeamID]=#i)>1
BEGIN
INSERT INTO #T
SELECT TOP 1 *
FROM [dbo].[TT]
WHERE [TeamID]=#i AND [Assigned_to] IS NOT NULL
ORDER BY [created_Date] DESC
END
ELSE
BEGIN
INSERT INTO #T
SELECT *
FROM [dbo].[TT]
WHERE [TeamID]=#i
END
FETCH NEXT FROM cur INTO #i
END
SELECT TicketID
, TeamID
, StatusID
, Assigned_to
, created_Date
FROM #T
GROUP BY TicketID
, TeamID
, StatusID
, created_Date
, Assigned_to
CLOSE cur
DEALLOCATE cur

Sql Server2005 query problem

i have a table which contains the following fields
Supervisorid
Empid
This is just like a referral program. A guy can refer 3 guys under him i.e,
3 is referring three guys namely 4 5 8 similarly 4 is referring 9 10 and 11 likewise 8 is referring 12, 13 it goes like this..
I want a query to get the total no of down line members under a guy say 3
You can make use of Recursive CTE.
Something like this
DECLARE #Table TABLE(
Supervisorid INT,
Empid INT
)
INSERT INTO #Table SELECT 3, 4
INSERT INTO #Table SELECT 3, 5
INSERT INTO #Table SELECT 3, 8
INSERT INTO #Table SELECT 4, 9
INSERT INTO #Table SELECT 4, 10
INSERT INTO #Table SELECT 4, 11
INSERT INTO #Table SELECT 8, 12
INSERT INTO #Table SELECT 8, 13
DECLARE #ID INT
SELECT #ID = 3
;WITH Vals AS (
SELECT *
FROM #Table
WHERE SuperVisorID = #ID
UNION ALL
SELECT v.SuperVisorID,
t.Empid
FROM Vals v INNER JOIN
#Table t ON v.Empid = t.Supervisorid
)
SELECT SuperVisorID,
COUNT(Empid) Total
FROM Vals
GROUP BY SuperVisorID