Sql Total Sum using no of row counts in a table - sql-server

i am trying to find the total marks for each student based on StudentId and MarksTypeId row count.
i have 3 tables
MarksType
----------------------------------
MarksTypeId | MarkType | Marks
----------------------------------
1 | Writing | 10
2 | Drawing | 30
3 | Singing | 20
----------------------------------
Students
--------------------------------
StudentId | Name | Address
--------------------------------
1 | John | USA
2 | Raja | India
3 | Paul | AUS
--------------------------------
MarksDetails -- Has two foreign keys
-------------------------------------------------------
MarksDetailsId | MarksTypeId | StudentId | Date
-------------------------------------------------------
1 | 3 | 1 | 18 jan
2 | 3 | 1 | 18 jan
3 | 1 | 3 | 19 jan
-------------------------------------------------------
This is my Desired Result :
------------------------------------
StudentId | Name | Total Marks
------------------------------------
1 | John | 40
2 | Raja | 0
3 | Paul | 10
------------------------------------
i mean if John sang two times a day, so using StudentId and MarksTypeId, i need his total Marks as result.
so far i did the following:
select Sum(MarksType.Marks) from MarksType inner join MarksDetails on MarksType.MarksTypeId=1
but the sum returns wrong total,
UPDATED OTHER ATTEMPTS:
this results total row count for each studentid
select MarksDetails.StudentId , COUNT(MarksDetails.StudentId ) as count from MarksDetails
group by MarksDetails.StudentId
this results Marks, with studentid and markstypeid
select MarksType.Marks, MarksType.MarksTypeId , MarksDetails.StudentId from MarksType inner join MarksDetails on MarksType.MarksTypeId = MarksDetails.StudentId
may i know what i am doing wrong.
Any help would be Great.

finally with kind guidance from sql developers and after making some research, here is the query with desired result, maybe useful for someone, enjoy !
SELECT Student.StudentId, Student.Name, sum(MarksType.Marks) as TotalMarks
FROM
MarksType
INNER JOIN
MarksDetails on MarksType.MarksTypeId = MarksDetails.MarksTypeId
INNER JOIN
Student on Student.StudentId = MarksDetails.StudentId
group by Student.Name,Student.StudentId

Related

I'm getting a rollup of the same value twice

I have table sellers where I list every single one of my sellers, and I added the column objective recently.
id |name | team_leader_id | team_leader | objective
--------------------------------------------------
1 |John | 50 | Mark | 30
2 |Jane | 66 | Ryu | 30
3 |Angela | 66 | Ryu | 45
4 |Arthur | 190 | Carol | 35
5 |Anthony| 20 | Adam | 50
I have another table sales where I link my sellers table on seller_id.
sale_id |seller_id |seller_name |item
-------------------------------------
56879 |2 |Jane |4P
23512 |2 |Jane |3P
54827 |2 |Jane |3P
12345 |5 |Anthony |4P
55435 |4 |Arthur |GSM
The query I'm trying is:
SELECT coalesce(seller.team_leader,'') team_leader,
coalesce(sales.seller_name,'TOTAL') seller_name,
seller.objective,
count(*) as quantity
FROM sales
JOIN seller ON seller.id = sales.seller_id
WHERE seller.team_leader_id = 66
GROUP BY seller.team_leader, ROLLUP(sales.seller_name), seller.objective
I noticed that the result I'm getting a duplicate of every line that now has an objective.
I think the problem is because my objective column is new, and I'm joining my sales table with my seller table, it counts the records I had before creating the objective column separately.
So, my expected result would be
team_leader | seller_name | objective | quantity
------------------------------------------------
Ryu | TOTAL | | 3
| Jane | 30 | 3
| Angela | 45 | 0
But this is what I'm getting
team_leader | seller_name | objective | quantity
------------------------------------------------
Ryu | TOTAL | | 1
Ryu | TOTAL | 30 | 2
| Jane | | 1
| Jane | 30 | 2
| Angela | 45 | 0
When the objective appears blank with Jane, it is a sale that she did before I added the objective column.
You can try the following :
SELECT case when seller.name is null then max(seller.team_leader) else '' end as team_leader,
isnull(seller.name,'TOTAL') seller_name,
case when seller.name is null then '' else sum(seller.objective) end objective,
count(sales.seller_id) as quantity
FROM seller
LEFT JOIN sales ON seller.id = sales.seller_id
WHERE seller.team_leader_id = 66
group by ROLLUP(seller.name)
order by team_leader desc, quantity desc
OR if you are okay with not using ROLLUP, you can get the exact same result using the following query.
;with cte as (
SELECT max(team_leader) team_leader,
max(name) seller_name,
max(objective) objective,
count(seller_id) as quantity
FROM seller
LEFT JOIN sales ON seller.id = sales.seller_id
WHERE seller.team_leader_id = 66
GROUP BY seller.id
)
SELECT team_leader, 'TOTAL' seller_name, '' objective, sum(quantity) quantity
FROM cte
GROUP BY team_leader
UNION ALL
SELECT '', seller_name, objective, quantity
FROM cte

Maximum Daisy Chain Length

I have a bunch of value pairs (Before, After) by users in a table. In ideal scenarios these values should form an unbroken chain. e.g.
| UserId | Before | After |
|--------|--------|-------|
| 1 | 0 | 10 |
| 1 | 10 | 20 |
| 1 | 20 | 30 |
| 1 | 30 | 40 |
| 1 | 40 | 30 |
| 1 | 30 | 52 |
| 1 | 52 | 0 |
Unfortunately, these records originate in multiple different tables and are imported into my investigation table. The other values in the table do not lend themselves to ordering (e.g. CreatedDate) due to some quirks in the system saving them out of order.
I need to produce a list of users with gaps in their data. e.g.
| UserId | Before | After |
|--------|--------|-------|
| 1 | 0 | 10 |
| 1 | 10 | 20 |
| 1 | 20 | 30 |
// Row Deleted (30->40)
| 1 | 40 | 30 |
| 1 | 30 | 52 |
| 1 | 52 | 0 |
I've looked at the other Daisy Chaining questions on SO (and online in general), but they all appear to be on a given problem space, where one value in the pair is always lower than the other in a predictable fashion. In my case, there can be increases or decreases.
Is there a way to quickly calculate the longest chain that can be created? I do have a CreatedAt column that would provide some (very rough) relative ordering - When the date is more than about 10 seconds apart, we could consider them orderable)
Are you not therefore simply after this to get the first row where the "chain" is broken?
SELECT UserID, Before, After
FROM dbo.YourTable YT
WHERE NOT EXISTS (SELECT 1
FROM dbo.YourTable NE
WHERE NE.After = YT.Before)
AND YT.Before != 0;
If you want to last row where the row where the "chain" is broken, just swap the aliases on the columns in the WHERE in the NOT EXISTS.
the following performs hierarchical recursion on your example data and calculates a "chain" count column called 'h_level'.
;with recur_cte([UserId], [Before], [After], h_level) as (
select [UserId], [Before], [After], 0
from dbo.test_table
where [Before] is null
union all
select tt.[UserId], tt.[Before], tt.[After], rc.h_level+1
from dbo.test_table tt join recur_cte rc on tt.UserId=rc.UserId
and tt.[Before]=rc.[After]
where tt.[Before]<tt.[after])
select * from recur_cte;
Results:
UserId Before After h_level
1 NULL 10 0
1 10 20 1
1 20 30 2
1 30 40 3
1 30 52 3
Is this helpful? Could you further define which rows to exclude?
If you want users that have more than one chain:
select t.UserID
from <T> as t left outer join <T> as t2
on t2.UserID = t.UserID and t2.Before = t.After
where t2.UserID is null
group by t.UserID
having count(*) > 1;

Return records based on min data in source and target if conditions satisfied in sql server

Hi I have data in sql server
Table : emp
Empid | deptid | doj | loc | Status|guid
1 | 10 | 2013-09-25 | hyd | 5 |10
1 | 10 | 2014-03-25 | che | 5 |11
1 | 10 | 2014-04-09 | pune | 5 |12
1 | 10 | 2015-01-22 | pune | 5 |13
2 | 20 | 2015-12-13 | beng | 5 |14
2 | 20 | 2014-12-17 | chen | 5 |15
2 | 20 | 2010-10-15 | beng | 4 |16
Table : empref
empid | deptid | startdate | status |guid
1 | 10 | 2013-10-02 | 2 |1
1 | 10 | 2014-04-09 | 2 |2
1 | 10 | 2015-12-09 | 1 |3
1 | 10 | 2015-01-30 | 2 |4
2 | 20 | 2015-12-14 | 2 |2
2 | 20 | 2015-12-15 | 2 |3
Both tables have common columns Empid + deptid
We need to consider emp table status=5 related records compare with empref table status=2
related records and emp table doj <= startdate --empref table and days difference between less than or equal to 30 days
If we find multiple records fall within 30 days in empref table startdate then we need to consider min(startdate) corresponding records
and that records need to be considered as update. Remain status values 4 or 1 no need in the return result set at this time.
If emp table status=5 related records compare with empref table status=2
related records and emp table doj <= startdate --empref table and daysdiffernce between less than or equal 30 days
If we find multiple records fall with in 30days in emp table doj then we need to consider min(doj) corresponding records
and that record needs to be considered as update in the filter column and guid information from empref table.
Remaining records considered as insert records in the filter column and guid information from emptable.
if emp table doj <=startdate--empref table condition not satisfied or
daysdiffernce not between less than or equal 30 days then that records we need to consider insert in the filter column
based on above tables I want output like below
Empid | Deptid | loc | Status | Filter | Doj |guid
1 | 10 | hyd | 5 | Update | 2013-09-25|1
1 | 10 | che | 5 | insert | 2014-03-25|11 ------min(startdate) corresponding record
1 | 10 | pune | 5 | update | 2014-04-09|2 --------mul
1 | 10 | Pune | 5 | update | 2015-01-22|4
2 | 20 | beng | 5 | update | 2015-12-13|2 --------------min(doj) record
2 | 20 | chen | 5 | insert | 2014-12-17|15
2 | 20 | beng | 4 | insert | 2010-10-15|16 -----this record not fall the above conditions
I tried like below
select s1.*
,'Update' as Filter from emp e join empref er
on e.empid=er.empid and
e.deptid=t.deptid
and e.status='5'
and er.status='2' and
e.doj<=er.startdate and datediff(dd,er.startdate,e.doj)*-1<=30
group by er.startdate,
e.empid,e.deptid.e.doj,e.loc
having e.startdate= min(er.startdate)
In the above query not given expected result. Please help me write this query to achieve this task in sql server.
It seems like the query you supplied is very close. Here is what I quickly put together. I haven't tested it against a lot of the possible options.
select e.Empid, er.deptid, e.loc, e.[status],
case when DATEDIFF(DAY, e.doj, er.startdate) <= 0 THEN 'INSERT'
ELSE 'UPDATE' END [DaysOffset],
e.doj
FROM #emp e inner join #empref ER
on e.Empid = er.empid and
e.deptid = er.deptid
where e.[status] = 5 and er.[status] = 2
and e.doj <= er.startdate and
DATEDIFF(DAY, e.doj, er.startdate) <= 30
The CASE statement is where it determines when the record is flagged for INSERT or UPDATE. With the datediff in the WHERE clause, it will only return records that are 30 days or less.

Select in SQL from 2 tables calculating average

I have 2 tables like that:
Student
ID | Name | Age
1 | Jonh | 20
2 | Smit | 19
3 | David | 28
4 | Simon | 18
5 | Kate | 17
6 | Marry | 20
Rating
Studen_ID | mark
1 | 10
1 | 5
2 | 7
3 | 9
3 | 8
I want to Select "Student" with Ratting" and show "Reporting" like that:
Reporting
ID | Name | Age | avg_mark
1 | Jonh | 20 | 15
2 | Smit | 19 | 7
3 | David | 28 | 17
4 | Simon | 18 | null
5 | Kate | 17 | null
6 | Marry | 20 | null
Please help me to do that. I am so stupid ><
Thanks
Nguyen
This query gets the students that have ratings, showing their name and average mark. If you want to show all of them regardless if the have or not rating, change the INNER by LEFT.
SELECT s.id, s.name, s.age, AVG(r.mark) AS avg_mark
FROM student s
INNER JOIN rating r ON s.id = r.student_id
GROUP BY s.id, s.name, s.age
Try this:
select id, name, age, sum(mark) as avg_mark from student
left join rating on student.id = rating.student_id
group by student.id, student.name, student.age
But note that in your example the avg_mark is actually the sum, not the average. If you want average (rounded) you should use avg(mark) instead like this:
select id, name, age, avg(mark) as avg_mark from student
left join rating on student.id = rating.student_id
group by student.id, student.name, student.age
Sample SQL Fiddle for both queries.

Sum worked hours

I have a issues table where users can log worked hours and estimate hours that looks like this
id | assignee | task | timespent | original_estimate | date
--------------------------------------------------------------------------
1 | john | design | 2 | 3 | 2013-01-01
2 | john | mockup | 2 | 3 | 2013-01-02
3 | john | design | 2 | 3 | 2013-01-01
4 | rick | mockup | 5 | 4 | 2013-01-04
And I need to sum and group the worked and estimated hours by task and date to get this
assignee | task | total_spent | total_estimate | date
------------------------------------------------------------------
john | design | 4 | 6 | 2013-01-01
john | mockup | 2 | 3 | 2013-01-02
rick | design | 5 | 4 | 2013-01-04
Ok, this is easy, I've already got this:
SELECT assignee, task, SUM(timespent) as total_spent, SUM(original_estimate) AS total_estimate, date FROM issues GROUP BY assignee, task, date
My problem is I need to also show the assignees that did not logged hours on any task that day, I mean:
assignee | task | total_spent | total_estimate | date
------------------------------------------------------------------
john | design | 4 | 6 | 2013-01-01
john | mockup | 2 | 3 | 2013-01-02
rick | design | 5 | 4 | 2013-01-04
pete | design | 0 | 0 | 2013-01-01
pete | mockup | 0 | 0 | 2013-01-02
liz | design | 0 | 0 | 2013-01-04
liz | mockup | 0 | 0 | 2013-01-04
The goal is to draw a chart like this http://jsfiddle.net/uUjst/embedded/result/
You need the Assignees in their own separate table to join from.
SELECT tblAssignee.Name, task, SUM(timespent) as total_spent, SUM(original_estimate) AS total_estimate, date
FROM tblAssignee
LEFT JOIN issue ON issues.assignee = tblAssignee.Name
GROUP BY tblAssignee.Name, task, date
Assuming that you have a user table, but not a tasks or dates table... meaning that we have to derive these values from the values present in issues:
;WITH dates AS (
SELECT DISTINCT date
FROM issues
), tasks AS (
SELECT DISTINCT task
FROM issues
)
SELECT
u.user as assignee,
t.task,
SUM(i.timespent) as total_spent,
SUM(i.original_estimate) AS total_estimate,
d.date
FROM
users u CROSS JOIN
dates d CROSS JOIN
tasks t LEFT OUTER JOIN
issues i ON
i.assignee = u.user
AND i.task = t.task
AND i.date = d.date
GROUP BY u.user, t.task, d.date
SELECT
A.name,
task,
ISNULL(SUM(timespent), 0) as total_spent,
ISNULL(SUM(original_estimate), 0) AS total_estimate,
date
FROM Assignee A
LEFT JOIN issue
ON issues.assignee = A.Name
GROUP BY A.name, task, date

Resources