enter image description here
Can anyone please help in getting the attached output?
Student Table
**Name Subject Marks**
Joan Maths 60
Joan Engish 80
Joan Science 70
Ray Maths 100
Ray Engish 90
Ray Science 75
Mike Maths 85
Mike Engish 95
Mike Science 88
Ashley Maths 69
Ashley Engish 77
Ashley Science 97
Output will be
Output
StudentName Maths Engish Science
Joan 60 80 70
Ray 100 90 75
Mike 85 95 88
Ashley 69 77 97
select [Name],
min(case when seq = 1 then marks end) Maths,
min(case when seq = 2 then marks end) Engish,
min(case when seq = 3 then marks end) Science
from
(
select [Name],[subject],marks,
row_number() over(partition by [Name] order by [subject]) seq
from Student
) d
group by [Name];
Related
Below is my table:
id order_number order_date order_details
---------------------------------------------
1 222 01-01-2020 44
2 222 02-01-2020 66
3 222 03-01-2020 20
4 223 03-01-2020 33
5 224 04-01-2020 55
6 225 02-01-2020 77
I want to have sum(order_details) where order_number = 222
like this table
order_date sum_order_details
----------------------------------
01-01-2020 130
02-01-2020 130
03-01-2020 130
I tried the below but it doesn't work
select order_number , order_date , sum(order_details) sum_orders from ex
group by order_number
having order_number = 222
It seems like you're after this is a windowed SUM:
SELECT order_date,
SUM(order_details) OVER () AS sum_orders
FROM YourTable
WHERE order_number = 222;
Using the following tables,
Productivity:
PRODUCTIVITYID PDATE EMPLOYEEID ROOMID ROOMS_SOLD SCR
81 03/26/2016 7499 21 56 43
82 03/26/2016 7566 42 - -
102 03/26/2016 7499 22 434 22
101 03/26/2016 7566 21 43 53
ProductivityD:
PRODUCTIVITYID WORKHRS MEALPANELTY DESCRIPTION
2 50 4 -
21 6.4 1 -
102 6 - -
81 1.32 - -
101 3.6 - -
Rooms:
ID ROOM PROPERTCODE
22 102 6325
41 103 6325
42 104 6325
43 105 6325
EMP:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7566 JONES MANAGER 7839 04/02/1981 2975 - 20
7788 SCOTT ANALYST 7566 12/09/1982 3000 - 20
7902 FORD ANALYST 7566 12/03/1981 3000 - 20
7369 SMITH CLERK 7902 12/17/1980 800 - 20
7499 ALLEN SALESMAN 7698 02/20/1981 1600 300 30
The following query is generating below output but I need to group employees and sum workhrs and then pivot RM_ROOM and RM_SCR
WITH pivot_data AS (
SELECT eNAME,workhrs,room, 'RM' as RM,SCR from PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID
)
SELECT *
FROM pivot_data
PIVOT (
MIN(room) as room,min(scr) as SCR --<-- pivot_clause
FOR RM--<-- pivot_for_clause
IN ('RM') --<-- pivot_in_clause
)
Current Output:
ENAME WORKHRS 'RM'_ROOM 'RM'_SCR
JONES 3.6 101 53
ALLEN 6 102 22
ALLEN 1.32 101 43
Desired Output:
ENAME WORKHRS 'RM'_ROOM 'RM'_SCR 'RM'_ROOM 'RM'_SCR
JONES 3.6 101 53 - -
ALLEN 7.32 101 43 102 22
You are pivoting on a fixed value, the string literal 'RM', so you're really not doing anything useful in the pivot - the output is the same as you'd get from running the 'pivot_data' query on its own:
SELECT eNAME,workhrs,room, SCR from PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID;
ENAME WORKHRS ROOM SCR
----- ---------- ---------- ----------
JONES 3.6 101 53
ALLEN 1.32 101 43
ALLEN 6 102 22
You want the aggregate workhrs for each employee, and a pivot of the rooms they sold. If you change that query to get the analytic sum of workhrs and a ranking of the room/scr values (and using modern join syntax) you get:
select e.ename, r.room, p.scr,
sum(d.workhrs) over (partition by e.ename) as wrkhrs,
rank() over (partition by e.ename order by r.room, p.scr) as rnk
from productivity p
join productivityd d on d.productivityid = p.productivityid
join emp e on e.empno=p.employeeid
join rooms r on r.id = p.roomid;
ENAME ROOM SCR WRKHRS RNK
----- ---------- ---------- ---------- ----------
ALLEN 101 43 7.32 1
ALLEN 102 22 7.32 2
JONES 101 53 3.6 1
You can then pivot on that generated rnk number:
with pivot_data as (
select e.ename, r.room, p.scr,
sum(d.workhrs) over (partition by e.ename) as wrkhrs,
rank() over (partition by e.ename order by r.room, p.scr) as rnk
from productivity p
join productivityd d on d.productivityid = p.productivityid
join emp e on e.empno=p.employeeid
join rooms r on r.id = p.roomid
)
select *
from pivot_data
pivot (
min(room) as room, min(scr) as scr --<-- pivot_clause
for rnk --<-- pivot_for_clause
in (1, 2, 3) --<-- pivot_in_clause
);
ENAME WRKHRS 1_ROOM 1_SCR 2_ROOM 2_SCR 3_ROOM 3_SCR
----- ---------- ---------- ---------- ---------- ---------- ---------- ----------
ALLEN 7.32 101 43 102 22
JONES 3.6 101 53
You need to know the maximum number of rooms any employee may have - i.e. the highest rnk could ever be - and include all of those in the in clause. Which means you're likely to end up with empty columns, as in this example where there is no data for 3_room or 3_scr. You can't avoid that though, unless you get an XML result or generate the query dynamically.
What you are saying makes no sense. What do you mean by "pivot RM_ROOM"? So I have to guess. I am guessing you want to group employees and sum workhrs, and then pivot the result. The "Output" you show seems to be the output for pivot_data, your subquery.
Your answer will only have eNAME and for each of them, a count of hours worked. So you don't need to SELECT the room numbers in the pivot_data subquery. You only need eNAME and workhrs. Then it is a simple matter of using the PIVOT syntax:
WITH pivot_data AS (
SELECT eNAME, workhrs FROM PRODUCTIVITY p,PRODUCTIVITYd d, emp e, ROOMS R
where p.PRODUCTIVITYID=d.PRODUCTIVITYID and e.empno=p.employeeid
AND R.ID=P.ROOMID
)
SELECT *
FROM pivot_data
PIVOT (
SUM(workhrs)
FOR eNAME IN ('JONES', 'ALLEN')
)
/
Output:
'JONES' 'ALLEN'
---------- ----------
3.6 7.32
I've sifted through the various sql-server tagged threads using AVERAGE and Cumulative as search terms. Various desperate answers, but I can't cobble them together for my needs. The use case is to find the initial average value (cumulative value/cumulative days on) for a time period when cumulative days on is greater than 60 and less than 90.
Below is a table where ID identifies the object, VALUE is the amount reported on a monthly basis and DAYSON is the number of days in that month where the object ran to produce the value. YEARMONTH is date value on which on can sort.
ID VALUE DASYON YEARMONTH
1 166 27 201502
1 1 2 201505
1 569 19 201507
1 312 19 201508
2 364 27 201502
2 328 31 201503
2 242 29 201504
2 273 31 201505
2 174 30 201506
2 188 25 201507
2 203 25 201508
3 474 28 201502
3 521 31 201503
3 465 30 201504
3 473 31 201505
3 434 30 201506
3 404 31 201507
I would like to create a summary table that averages the cumulative value divided by the cumulative days uniquely for each ID where cumulative days is greater than 60 and less than 90. Below is a table that with the cumulative values. (I generated this in Excel)
ID VALUE cumValue DASYON cumDaysOn YEARMONTH
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
I try this based on other threads:
SELECT
ID,
Value,
SUM(Value) OVER (ORDER BY ID, YearMonth) [cumValue],
DaysOn,
SUM (DaysOn) OVER (Order by ID, YearMonth) as cumDaysOn,
YearMonth
FROM table
WHERE DAYSON > 0 and Liquid > 0 and YearMonth > 201501
GROUP BY ID, YearMonth, Value, DaysOn
ORDER BY ID, yearmonth
I can't get it to iterate over the ID; it just keeps summing down the column. If I could create a table or view like the one above, then I could always use a select statement and divide cumvalue by cumdayson.
Below is a table to show where I would get the initial average value (InititalAverageValue) based on the criteria:
ID VALUE cumValue DASYON cumDaysOn YEARMONTH InitalAvgValue
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508 55
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504 32
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504 18
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
Ultimately what I desire is table as such:
ID InitalAvgValue
1 55
2 32
3 18
Thanks in advance for any help.
The crux is that you need a running total. There are several approaches to calculating running totals, but they have various tradeoffs between simplicity and performance. The "best" approach depends on the expected size of your data set and whether you are using SQL Server 2012 or an earlier version. The following article describes some different options along with the pros and cons:
http://sqlperformance.com/2012/07/t-sql-queries/running-totals
Here's a quick example using correlated subqueries, which may be reasonable for small data sets, but likely would not scale well to larger data:
SELECT
ID,
ROUND(AVG(CAST(CumulativeValue AS FLOAT) / CAST(CumulativeDaysOn AS FLOAT)), 1) AS Average
FROM
(
SELECT
ID,
Value,
DaysOn,
(SELECT SUM(Value) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeValue,
(SELECT SUM(DaysOn) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeDaysOn
FROM
ExampleTable t1
) AS ExampleWithTotals
WHERE
CumulativeDaysOn > 60 AND CumulativeDaysOn < 90
GROUP BY
ID
ORDER BY
ID
;
Output:
ID Average
1 15.6
2 10.7
3 16.4
I have the following query that gave me the results of duplicate rows and that is not what I wanted
SELECT
OM_ITEM_MASTER.part_no PARTNO,
item_description DESCRIPTION,
item_manufacturer MANUFACTURER,
FM_PRICE_LIST.cost_price COSTPRICE
FROM OM_ITEM_MASTER, FM_PRICE_LIST
ORDER BY item_description
Result:
PARTNO DESCRIPTION MANUFACTURER COSTPRICE
NT321 NULL NULL 87665
NT321 NULL NULL 2957
NT321 NULL NULL 150
NT321 NULL NULL 67895
NT321 NULL NULL 5000
NT321 NULL NULL 5000
NT321 NULL NULL 459
NT321 NULL NULL 459
NT321 NULL NULL 45
NT321 NULL NULL 45
NT321 NULL NULL 45
NT321 NULL NULL 45
demore 87665
demore 2957
demore 150
demore 67895
demore 5000
demore 5000
demore 459
demore 459
demore 45
demore 45
demore 45
demore 45
4565 anne balls 87665
4565 anne balls 2957
4565 anne balls 150
4565 anne balls 67895
4565 anne balls 5000
4565 anne balls 5000
4565 anne balls 459
4565 anne balls 459
4565 anne balls 45
4565 anne balls 45
4565 anne balls 45
4565 anne balls 45
345 CRUNK WABCO 87665
345 CRUNK WABCO 2957
345 CRUNK WABCO 150
345 CRUNK WABCO 67895
345 CRUNK WABCO 5000
345 CRUNK WABCO 5000
345 CRUNK WABCO 459
345 CRUNK WABCO 459
345 CRUNK WABCO 45
345 CRUNK WABCO 45
345 CRUNK WABCO 45
345 CRUNK WABCO 45
24 desktop ibm 87665
24 desktop ibm 2957
24 desktop ibm 150
24 desktop ibm 67895
24 desktop ibm 5000
24 desktop ibm 5000
24 desktop ibm 459
24 desktop ibm 459
24 desktop ibm 45
24 desktop ibm 45
24 desktop ibm 45
24 desktop ibm 45
trtrt fdfd fdfdf 87665
trtrt fdfd fdfdf 2957
trtrt fdfd fdfdf 150
trtrt fdfd fdfdf 67895
trtrt fdfd fdfdf 5000
trtrt fdfd fdfdf 5000
trtrt fdfd fdfdf 459
trtrt fdfd fdfdf 459
trtrt fdfd fdfdf 45
trtrt fdfd fdfdf 45
trtrt fdfd fdfdf 45
trtrt fdfd fdfdf 45
TX900 FR NULL 87665
TX900 FR NULL 2957
TX900 FR NULL 150
TX900 FR NULL 67895
TX900 FR NULL 5000
TX900 FR NULL 5000
TX900 FR NULL 459
TX900 FR NULL 459
TX900 FR NULL 45
TX900 FR NULL 45
TX900 FR NULL 45
TX900 FR NULL 45
26 gdrn opiyo 87665
26 gdrn opiyo 2957
1 laptop microsoft 87665
1 laptop microsoft 2957
1 laptop microsoft 150
1 laptop microsoft 67895
1 laptop microsoft 5000
1 laptop microsoft 5000
1 laptop microsoft 459
1 laptop microsoft 459
1 laptop microsoft 45
1 laptop microsoft 45
1 laptop microsoft 45
1 laptop microsoft 45
23 laptop microsoft 87665
23 laptop microsoft 2957
23 laptop microsoft 150
23 laptop microsoft 67895
23 laptop microsoft 5000
23 laptop microsoft 5000
23 laptop microsoft 459
23 laptop microsoft 459
23 laptop microsoft 45
23 laptop microsoft 45
23 laptop microsoft 45
23 laptop microsoft 45
567 originals holly 87665
567 originals holly 2957
567 originals holly 150
567 originals holly 67895
567 originals holly 5000
567 originals holly 5000
567 originals holly 459
567 originals holly 459
567 originals holly 45
567 originals holly 45
567 originals holly 45
567 originals holly 45
2 pc ibm 87665
2 pc ibm 2957
2 pc ibm 150
2 pc ibm 67895
2 pc ibm 5000
2 pc ibm 5000
2 pc ibm 459
2 pc ibm 459
2 pc ibm 45
2 pc ibm 45
2 pc ibm 45
2 pc ibm 45
123 qwe asd 87665
123 qwe asd 2957
123 qwe asd 150
123 qwe asd 67895
123 qwe asd 5000
123 qwe asd 5000
123 qwe asd 459
123 qwe asd 459
123 qwe asd 45
123 qwe asd 45
123 qwe asd 45
123 qwe asd 45
347 ROOT MAN 87665
347 ROOT MAN 2957
347 ROOT MAN 150
347 ROOT MAN 67895
347 ROOT MAN 5000
347 ROOT MAN 5000
347 ROOT MAN 459
347 ROOT MAN 459
347 ROOT MAN 45
347 ROOT MAN 45
347 ROOT MAN 45
347 ROOT MAN 45
rt56 wer dfgg 87665
rt56 wer dfgg 2957
rt56 wer dfgg 150
rt56 wer dfgg 67895
rt56 wer dfgg 5000
rt56 wer dfgg 5000
rt56 wer dfgg 459
rt56 wer dfgg 459
rt56 wer dfgg 45
rt56 wer dfgg 45
rt56 wer dfgg 45
rt56 wer dfgg 45
then i made the following changes to the query
SELECT distinct
OM_ITEM_MASTER.part_no PARTNO,
item_description DESCRIPTION,
item_manufacturer MANUFACTURER,
FM_PRICE_LIST.cost_price COSTPRICE
FROM OM_ITEM_MASTER
inner join FM_PRICE_LIST on OM_ITEM_MASTER.[PART_NO] = FM_PRICE_LIST.[PART_NO]
order by ITEM_DESCRIPTION
but this displays only a single row and I want all the rows to be displayed but not duplicates. Below is the result:
PARTNO DESCRIPTION MANUFACTURER COSTPRICE
NT321 NULL NULL 87665
In the first example you are getting a cartesian product of the two tables as you haven't defined any join condition, whereas in the second example you have defined an inner join condition which limits the result set to those items present in both tables. Maybe there are products missing in the FM_PRICE_LIST table.
Try changing the inner join to a left join to include all products from the OM_ITEM_MASTER table even if there is no corresponding row in the other table.
Also, your sample data doesn't match the queries which is a bit confusing.
I have a table that lists visits to a clinic. I'd like to get a "histogram" of sorts showing how frequently patients visit the clinic along with totals. Here's some sample code (tested under MS SQL Server 2005) to show what I'm talking about:
CREATE TABLE #test (
visit_id int IDENTITY(1,1),
patient_id int
);
DECLARE #num_patients int;
SELECT #num_patients = 1000 + ABS(CHECKSUM(NEWID())) % 250;
INSERT INTO #test (patient_id)
SELECT TOP 15 PERCENT ABS(CHECKSUM(NEWID())) % #num_patients
FROM sysobjects a, sysobjects b;
-- SELECT COUNT(*) AS total_visits FROM #test;
-- SELECT COUNT(DISTINCT patient_id) AS distinct_patients FROM #test;
SELECT CASE GROUPING(num_pat_visits) WHEN 1 THEN 'Total'
ELSE CAST(num_pat_visits AS varchar(5)) END AS num_pat_visits,
COUNT(*) AS num_patients, num_pat_visits * COUNT(*) AS tot_pat_visit
FROM
(SELECT patient_id, COUNT(*) AS num_pat_visits FROM #test GROUP BY patient_id) a
GROUP BY num_pat_visits WITH ROLLUP
ORDER BY CAST(num_pat_visits AS int) DESC;
This gets me almost to where I want:
num_pat_visits num_patients tot_pat_visit
-------------- ------------ -------------
60 1 60
54 2 108
52 2 104
51 4 204
50 3 150
49 3 147
48 7 336
47 7 329
46 15 690
45 15 675
44 29 1276
43 36 1548
42 45 1890
41 45 1845
40 59 2360
39 71 2769
38 51 1938
37 72 2664
36 77 2772
35 74 2590
34 72 2448
33 82 2706
32 90 2880
31 74 2294
30 69 2070
29 47 1363
28 30 840
27 27 729
26 26 676
25 21 525
24 13 312
23 4 92
22 5 110
21 4 84
20 2 40
18 2 36
Total 1186 NULL
However, I can't seem to get SQL Server to display the total number of visits where it says NULL on the total row.
Any ideas?
I think you can just do:
sum(num_pat_visits) as tot_pat_visit
SELECT CASE GROUPING(num_pat_visits) WHEN 1 THEN 'Total'
ELSE CAST(num_pat_visits AS varchar(5)) END AS num_pat_visits,
COUNT(*) AS num_patients,
--num_pat_visits * COUNT(*) AS tot_pat_visit
sum(num_pat_visits) as tot_pat_visit
FROM
(SELECT patient_id, COUNT(*) AS num_pat_visits FROM #test GROUP BY patient_id) a
GROUP BY num_pat_visits WITH ROLLUP
ORDER BY CAST(num_pat_visits AS int) DESC;