Compare rows value - sql-server

ID mobileno dateofregistration registrationstate
44 1674174925 2011-04-18 10:17:30.670 0
45 1677864168 2011-04-18 10:20:22.450 1
46 1677864161 2011-04-18 20:47:35.293 0
47 1674174925 2011-04-19 09:28:55.200 1
48 1674174925 2011-04-19 09:28:56.200 0
49 1674174925 2011-04-19 09:28:57.200 1
50 1674174925 2011-04-18 10:17:30.670 0
51 1677864168 2011-04-18 10:20:22.450 1
52 1677864161 2011-04-20 20:47:35.293 0
53 1674174925 2011-04-22 09:28:55.200 1
54 1674174925 2011-04-28 09:28:56.200 0
55 1674174925 2011-04-28 09:28:57.200 1
My problem is how to count the rows with the following conditions:
registrationstate = 1 and datediff(day,dateofregistration) > 30 for the individual mobile no.
Here the result will be 1

first of all, datediff requires 3 arguments
DATEDIFF ( datepart , startdate , enddate )
I assume that you want to compare with today's date, so you can use getdate()
select * from yourtable
where registrationstate = 1
and datediff( day, dateofregistration, getdate() ) > 30
if getdate() return 2011-05-04 , you will get the following output
------------------------------------------------------------
ID mobileno dateofregistration registrationstate
------------------------------------------------------------
45 1677864168 2011-04-18 10:20:22.450 1
47 1674174925 2011-04-19 09:28:55.200 1
49 1674174925 2011-04-19 09:28:57.200 1
51 1677864168 2011-04-18 10:20:22.450 1
53 1674174925 2011-04-22 09:28:55.200 1
55 1674174925 2011-04-28 09:28:57.200 1
------------------------------------------------------------
now you want to group the results by mobileno and also return the number of rows per group. You can use the COUNT(*) aggregate function to return the number of rows per group
select COUNT(*) as total, mobileno from yourtable
where registrationstate = 1
and datediff( day, dateofregistration, getdate() ) > 30
group by mobileno
you will get the following output
------------------------------------------------------------
mobileno total
------------------------------------------------------------
1677864168 2
1674174925 4
------------------------------------------------------------

Related

Need to match ClockIn with Clock out, multiple clocks on same day SQL

I'm trying to get the clock in and clock out times to correspond to each other so that I can calculate hours worked/amount of breaks/time worked within working hours etc. I have a 'Clocking' table that looks like this:
MOCK DATA:
Clock_ID
Employee_ID
Office
Clock_Date
Clock_Time
ActivityID
1
83
Pretoria CBD
29/03/2022
06:43:00
1
2
55
Pretoria CBD
29/03/2022
06:45:00
1
3
54
Pretoria CBD
29/03/2022
07:00:00
1
4
80
Pretoria CBD
29/03/2022
07:00:00
1
5
75
Pretoria CBD
29/03/2022
07:05:00
1
6
54
Pretoria CBD
29/03/2022
10:59:00
2
7
54
Pretoria CBD
29/03/2022
11:50:00
1
8
55
Pretoria CBD
29/03/2022
12:18:00
2
9
55
Pretoria CBD
29/03/2022
12:30:00
1
10
83
Pretoria CBD
29/03/2022
13:03:00
2
11
80
Pretoria CBD
29/03/2022
13:04:00
2
12
83
Pretoria CBD
29/03/2022
13:39:00
1
13
80
Pretoria CBD
29/03/2022
13:39:00
1
14
75
Pretoria CBD
29/03/2022
15:59:00
2
15
54
Pretoria CBD
29/03/2022
16:00:00
2
16
83
Pretoria CBD
29/03/2022
16:00:00
2
17
80
Pretoria CBD
29/03/2022
16:00:00
2
18
55
Pretoria CBD
29/03/2022
16:00:00
2
19
83
Pretoria CBD
30/03/2022
06:46:00
1
20
55
Pretoria CBD
30/03/2022
06:51:00
1
21
80
Pretoria CBD
30/03/2022
06:54:00
1
22
54
Pretoria CBD
30/03/2022
06:54:00
1
23
54
Pretoria CBD
30/03/2022
11:24:00
2
24
54
Pretoria CBD
30/03/2022
12:11:00
1
25
80
Pretoria CBD
30/03/2022
13:03:00
2
26
80
Pretoria CBD
30/03/2022
14:10:00
1
27
54
Pretoria CBD
30/03/2022
16:01:00
2
28
80
Pretoria CBD
30/03/2022
16:01:00
2
29
83
Pretoria CBD
30/03/2022
16:01:00
2
30
55
Pretoria CBD
30/03/2022
16:05:00
2
31
83
Pretoria CBD
31/03/2022
06:48:00
1
32
55
Pretoria CBD
31/03/2022
06:53:00
1
33
54
Pretoria CBD
31/03/2022
06:55:00
1
34
80
Pretoria CBD
31/03/2022
07:09:00
1
35
54
Pretoria CBD
31/03/2022
12:02:00
2
36
54
Pretoria CBD
31/03/2022
12:09:00
1
37
83
Pretoria CBD
31/03/2022
12:34:00
2
38
80
Pretoria CBD
31/03/2022
12:34:00
2
39
83
Pretoria CBD
31/03/2022
13:09:00
1
40
80
Pretoria CBD
31/03/2022
13:09:00
1
41
55
Pretoria CBD
31/03/2022
13:32:00
2
42
54
Pretoria CBD
31/03/2022
15:56:00
2
The ActivityID determines whether it is a 'Clock IN' or 'Clock OUT'
I have used hash tables to separate the data into #clockIN and #clockOUT tables for any given Employee_ID as seen below:
#ClockIN
#ClockOUT
I tried using an inner join on the 'Clock_Date' on the tables to correspond clockINs to clockOUTs, but I get multiple clockOUTS for one clockIN due to the fact that employees can clockIN and OUT multiple times in a day: See below:
As you can see, the records are matched incorrectly, and a just joined on the date.
I cannot think of a way to correctly join them I.e ClockIn at 7:30 must be joined with the EARLIEST clock out on the same day and the next clockIN for that day must be the second earliest ClockIN which must be joined with the second earliest Clock OUT etc.
Would I have to use a cursor? if so, how could I implement that?
I will past all the SQL I used to get to this point.
Drop Table #ClockIn
Drop Table #ClockOut
DROP Table #SortedTimes
DROP Table #WorkBoundries
SELECT Clock_ID, Clock_Date AS Date, Clock_Time
INTO #ClockIn
FROM Clocking
WHERE Employee_ID = 82 AND ActivityID = 1
SELECT * FROM #ClockIn
SELECT Clock_ID, Clock_Date AS Date, Clock_Time
INTO #ClockOut
FROM Clocking
WHERE Employee_ID = 82 AND ActivityID = 2
SELECT * FROM #ClockOut
SELECT #ClockIn.Clock_Time As clockIN, #ClockOut.Clock_Time as ClockOUT, #ClockIn.Date INTO #SortedTimes
FROM #ClockIn
INNER JOIN #ClockOut On #ClockOut.Date = #ClockIN.Date
ORDER BY #ClockIn.Date ASC
SELECT * FROM #SortedTimes
SELECT MIN(clockIn)As TimeIn, MAX(ClockOUT) As TimeOut, [Date] As DayWorked INTO #WorkBoundries
FROM #SortedTimes
GROUP BY [Date]
SELECT * FROM #WorkBoundries
The #WorkBoundries is just to see if the person is clocking IN/OUT within their work hours or not.
Thank you in advance for any assistance
Maybe this can help you
select e.empid,
e.clockdate,
e.clocktime as starttime,
o.clocktime as endtime
from emp e
outer apply (select top 1 e2.clocktime
from emp e2
where e2.empid = e.empid
and e2.activity = 2
and e2.clockdate = e.clockdate
and e2.clocktime > e.clocktime
order by e2.clocktime
) o
where e.activity = 1
order by e.empid, e.clocktime
DBFiddle here
it results in this
empid
clockdate
starttime
endtime
55
2022-03-29
06:45:00.0000000
12:18:00.0000000
55
2022-03-29
12:30:00.0000000
null
83
2022-03-29
06:43:00.0000000
13:03:00.0000000
83
2022-03-29
13:39:00.0000000
16:00:00.0000000
You can do this in a single scan of the base table, and no joins, by using window functions:
WITH NextValues AS (
SELECT *,
NextClockOut = LEAD(CASE WHEN c.ActivityID = 2 THEN c.Clock_Time END)
OVER (PARTITION BY c.Office, c.Employee_ID, c.Clock_Date
ORDER BY c.Clock_Time)
FROM Clocking c
)
SELECT
nv.Employee_ID,
nv.Office,
nv.Clock_Date,
ClockIn = nv.Clock_Time,
ClockOut = nv.NextClockOut
FROM NextValues nv
WHERE nv.ActivityID = 1;
db<>fiddle

query max date of all customers that falls under a where condition

I would like to query the max date only of all customers that has a value of 25.
Table1
cust_id Date Value
1 2019-10-01 25
1 2019-10-19 35
1 2018-08-27 29
1 2019-07-09 35
1 2019-10-15 55
2 2019-09-26 45
2 2019-10-19 31
2 2019-07-19 8
2 2019-10-02 28
3 2019-09-02 36
3 2019-08-15 39
4 2019-10-15 37
4 2019-10-16 36
4 2018-11-18 27
wrote this query:
select
t1.value,
max(t1.date) as max_date
from table1 t1
where
(t1.date >= '2019-09-30 and t1.date <= 2019-10-31)
and t1.value > 25
group by t1.value
but I am getting:
cust_id Date Value
1 2019-10-01 25
1 2019-10-19 35
1 2019-10-15 55
2 2019-10-19 31
2 2019-10-02 28
4 2019-10-15 37
4 2019-10-16 36
would like to only see the last data entry that is over 25. Something like this:
cust_id Date Value
1 2019-10-19 35
2 2019-10-19 31
4 2018-11-16 36

How to Sort Amount Number Negative and Positive Number In SQL server

I have working SQL Server.I have More than 20000 Lines Using SQL server.I have column Filed Name Amount. in Amount Filed Inserted negative and Positive Number .Now I want Sort Amount Field Negative and Positive Number
Example Like :
Entity ExpenseTypeCode ExpenseType Amount
11 043 Hotel 5
12 044 travel 23
13 045 drink 55
14 046 Dinner 23
15 047 airline 556
16 048 Hotel -5
I how Like More than 30000 LINES .IN my table i have Expense type but negative and Positive value
I want Sort My table Like negative and Positive order same value
Entity ExpenseTypeCode ExpenseType Amount
11 043 Hotel 5
16 048 Hotel -5 --> Want sort like this
12 044 travel 23
13 045 drink 55
14 046 Dinner 23
15 047 airline 556
How can i sort my table liKE ?
Use ABS Function in sorting:
ABS() : It will convert your negative value to positive
SELECT
*
FROM TableName
Order BY ABS(Amount)
If you wants if negative and positive value same and order should consider positive first then:
SELECT
*
FROM TableName
Order BY ABS(Amount),Amount*-1
Example:
Initial
Output
select * from #t t
order by expensetype,
case when amount > 0 then 1 else 2 end
result
Entity ExpenseTypeCode ExpenseType Amount
----------- --------------- ----------- -----------
15 47 airline 556
14 46 Dinner 23
13 45 drink 55
11 43 Hotel 5
16 48 Hotel -5
12 44 travel 23
If you are looking for matching pairs then something like this might be what you want
declare #t table(Entity int, ExpenseTypeCode int, ExpenseType varchar(10), Amount int)
insert into #t values
( 11, 043, 'Hotel' , 6),
( 8, 043, 'Hotel' , 5),
( 9, 043, 'Hotel' , 5),
( 10, 043, 'Hotel' , 5),
( 12, 044, 'travel' , 23),
( 13, 045, 'drink' , 55),
( 14, 046, 'Dinner' , 23),
( 15, 047, 'airline' , 556),
( 16, 048, 'Hotel' , -5),
( 17, 048, 'Hotel' , -5),
( 18, 043, 'Hotel' , -6),
( 19, 043, 'Hotel' , -6)
select t.*,row_number() over(partition by t.ExpenseType, t.amount order by t.entity) rn,t.amount as absamount
from #t t
where t.amount > 0
union all
select t.*,row_number() over(partition by t.ExpenseTypeCode, t.amount order by t.entity) rn, abs(t.amount)
from #t t
where t.amount < 0
order by t.expensetype,absamount,rn,t.amount desc
result
Entity ExpenseTypeCode ExpenseType Amount rn absamount
----------- --------------- ----------- ----------- -------------------- -----------
15 47 airline 556 1 556
14 46 Dinner 23 1 23
13 45 drink 55 1 55
8 43 Hotel 5 1 5
16 48 Hotel -5 1 5
9 43 Hotel 5 2 5
17 48 Hotel -5 2 5
10 43 Hotel 5 3 5
11 43 Hotel 6 1 6
18 43 Hotel -6 1 6
19 43 Hotel -6 2 6
12 44 travel 23 1 23
or possibly a full join
select s.*,t.* from
(
select t.*,row_number() over(partition by t.ExpenseType, t.amount order by t.entity) rn
from #t t
where t.amount > 0
) s
full join
(
select t.*,row_number() over(partition by t.ExpenseTypeCode, t.amount order by t.entity) rn
from #t t
where t.amount < 0
) t on t.expensetype = s.expensetype and t.rn = s.rn and abs(t.amount) = s.amount
order by s.expensetype
Entity ExpenseTypeCode ExpenseType Amount rn Entity ExpenseTypeCode ExpenseType Amount rn
----------- --------------- ----------- ----------- -------------------- ----------- --------------- ----------- ----------- --------------------
NULL NULL NULL NULL NULL 19 43 Hotel -6 2
15 47 airline 556 1 NULL NULL NULL NULL NULL
14 46 Dinner 23 1 NULL NULL NULL NULL NULL
13 45 drink 55 1 NULL NULL NULL NULL NULL
11 43 Hotel 6 1 18 43 Hotel -6 1
10 43 Hotel 5 3 NULL NULL NULL NULL NULL
8 43 Hotel 5 1 16 48 Hotel -5 1
9 43 Hotel 5 2 17 48 Hotel -5 2
12 44 travel 23 1 NULL NULL NULL NULL NULL

SQL Server: create multiplication table

I need help regarding this problem. I need to create a function that will accept an integer and return a 10x10 multiplication table starting from the input value.
Sample can be seen below.
INPUT = 2
OUTPUT =
2 3 4 5 6 7 8 9 10 11
2 4 6 8 10 12 14 16 18 20 22
3 6 9 12 15 18 21 24 27 30 33
4 8 12 16 20 24 28 32 36 40 44
5 10 15 20 25 30 35 40 45 50 55
6 12 18 24 30 36 42 48 54 60 66
7 14 21 28 35 42 49 56 63 70 77
8 16 24 32 40 48 56 64 72 80 88
9 18 27 36 45 54 63 72 81 90 99
10 20 30 40 50 60 70 80 90 100 110
11 22 33 44 55 66 77 88 99 110 121
try this:
DECLARE #StartNumber int
,#EndNumber int
SELECT #StartNumber=2
,#EndNumber=#StartNumber+9
;WITH AllNumbers AS
(
SELECT #StartNumber AS Number
, #StartNumber*(#StartNumber+0) AS Number1
, #StartNumber*(#StartNumber+1) AS Number2
, #StartNumber*(#StartNumber+2) AS Number3
, #StartNumber*(#StartNumber+3) AS Number4
, #StartNumber*(#StartNumber+4) AS Number5
, #StartNumber*(#StartNumber+5) AS Number6
, #StartNumber*(#StartNumber+6) AS Number7
, #StartNumber*(#StartNumber+7) AS Number8
, #StartNumber*(#StartNumber+8) AS Number9
, #StartNumber*(#StartNumber+9) AS Number10
UNION ALL
SELECT Number+1
, (Number+1)*(#StartNumber+0) AS Number1
, (Number+1)*(#StartNumber+1) AS Number2
, (Number+1)*(#StartNumber+2) AS Number3
, (Number+1)*(#StartNumber+3) AS Number4
, (Number+1)*(#StartNumber+4) AS Number5
, (Number+1)*(#StartNumber+5) AS Number6
, (Number+1)*(#StartNumber+6) AS Number7
, (Number+1)*(#StartNumber+7) AS Number8
, (Number+1)*(#StartNumber+8) AS Number9
, (Number+1)*(#StartNumber+9) AS Number10
FROM AllNumbers
WHERE Number<#EndNumber
)
SELECT * FROM AllNumbers a
OUTPUT:
Number Number1 Number2 Number3 Number4 Number5 Number6 Number7 Number8 Number9 Number10
------- ------- ------- ------- ------- ------- ------- ------- ------- ------- --------
2 4 6 8 10 12 14 16 18 20 22
3 6 9 12 15 18 21 24 27 30 33
4 8 12 16 20 24 28 32 36 40 44
5 10 15 20 25 30 35 40 45 50 55
6 12 18 24 30 36 42 48 54 60 66
7 14 21 28 35 42 49 56 63 70 77
8 16 24 32 40 48 56 64 72 80 88
9 18 27 36 45 54 63 72 81 90 99
10 20 30 40 50 60 70 80 90 100 110
11 22 33 44 55 66 77 88 99 110 121
(10 row(s) affected)
make it dynamic SQL to get the proper column names:
DECLARE #SQL varchar(5000)
,#StartNumber int
SET #StartNumber=2
SET #SQL='
DECLARE #StartNumber int
,#EndNumber int
SELECT #StartNumber='+CONVERT(varchar(3),#StartNumber)+'
,#EndNumber=#StartNumber+9
;WITH AllNumbers AS
(
SELECT #StartNumber AS [ ]
, #StartNumber*(#StartNumber+0) AS ['+CONVERT(varchar(3),#StartNumber+0)+']
, #StartNumber*(#StartNumber+1) AS ['+CONVERT(varchar(3),#StartNumber+1)+']
, #StartNumber*(#StartNumber+2) AS ['+CONVERT(varchar(3),#StartNumber+2)+']
, #StartNumber*(#StartNumber+3) AS ['+CONVERT(varchar(3),#StartNumber+3)+']
, #StartNumber*(#StartNumber+4) AS ['+CONVERT(varchar(3),#StartNumber+4)+']
, #StartNumber*(#StartNumber+5) AS ['+CONVERT(varchar(3),#StartNumber+5)+']
, #StartNumber*(#StartNumber+6) AS ['+CONVERT(varchar(3),#StartNumber+6)+']
, #StartNumber*(#StartNumber+7) AS ['+CONVERT(varchar(3),#StartNumber+7)+']
, #StartNumber*(#StartNumber+8) AS ['+CONVERT(varchar(3),#StartNumber+8)+']
, #StartNumber*(#StartNumber+9) AS ['+CONVERT(varchar(3),#StartNumber+9)+']
UNION ALL
SELECT [ ]+1
, ([ ]+1)*(#StartNumber+0) AS ['+CONVERT(varchar(3),#StartNumber+0)+']
, ([ ]+1)*(#StartNumber+1) AS ['+CONVERT(varchar(3),#StartNumber+1)+']
, ([ ]+1)*(#StartNumber+2) AS ['+CONVERT(varchar(3),#StartNumber+2)+']
, ([ ]+1)*(#StartNumber+3) AS ['+CONVERT(varchar(3),#StartNumber+3)+']
, ([ ]+1)*(#StartNumber+4) AS ['+CONVERT(varchar(3),#StartNumber+4)+']
, ([ ]+1)*(#StartNumber+5) AS ['+CONVERT(varchar(3),#StartNumber+5)+']
, ([ ]+1)*(#StartNumber+6) AS ['+CONVERT(varchar(3),#StartNumber+6)+']
, ([ ]+1)*(#StartNumber+7) AS ['+CONVERT(varchar(3),#StartNumber+7)+']
, ([ ]+1)*(#StartNumber+8) AS ['+CONVERT(varchar(3),#StartNumber+8)+']
, ([ ]+1)*(#StartNumber+9) AS ['+CONVERT(varchar(3),#StartNumber+9)+']
FROM AllNumbers
WHERE [ ]<#EndNumber
)
SELECT * FROM AllNumbers a'
exec(#SQL)
OUTPUT:
2 3 4 5 6 7 8 9 10 11
------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
2 4 6 8 10 12 14 16 18 20 22
3 6 9 12 15 18 21 24 27 30 33
4 8 12 16 20 24 28 32 36 40 44
5 10 15 20 25 30 35 40 45 50 55
6 12 18 24 30 36 42 48 54 60 66
7 14 21 28 35 42 49 56 63 70 77
8 16 24 32 40 48 56 64 72 80 88
9 18 27 36 45 54 63 72 81 90 99
10 20 30 40 50 60 70 80 90 100 110
11 22 33 44 55 66 77 88 99 110 121
(10 row(s) affected)
Here's a cross join solution for you:
DECLARE #StartNum int;
SET #StartNum = 1;
WITH numbers AS (
SELECT
N = #StartNum + number
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 0 AND 9
),
products AS (
SELECT
n1.N,
PivotN = n2.N,
P = n1.N * n2.N
FROM numbers n1
CROSS JOIN numbers n2
)
SELECT
N,
P0 = MAX(CASE PivotN WHEN #StartNum + 0 THEN P END),
P1 = MAX(CASE PivotN WHEN #StartNum + 1 THEN P END),
P2 = MAX(CASE PivotN WHEN #StartNum + 2 THEN P END),
P3 = MAX(CASE PivotN WHEN #StartNum + 3 THEN P END),
P4 = MAX(CASE PivotN WHEN #StartNum + 4 THEN P END),
P5 = MAX(CASE PivotN WHEN #StartNum + 5 THEN P END),
P6 = MAX(CASE PivotN WHEN #StartNum + 6 THEN P END),
P7 = MAX(CASE PivotN WHEN #StartNum + 7 THEN P END),
P8 = MAX(CASE PivotN WHEN #StartNum + 8 THEN P END),
P9 = MAX(CASE PivotN WHEN #StartNum + 9 THEN P END)
FROM products
GROUP BY N
ORDER BY N
Like with KM's solution, it is possible to rewrite the above query to have dynamic column names, but then you wouldn't be able to use the resulting query in a TVF. A stored procedure would do. Here's a dynamic version of the same script:
DECLARE #StartNum int, #NumColumns varchar(max), #sql varchar(max);
SET #StartNum = 2;
SELECT
#NumColumns = COALESCE(#NumColumns + ', ', '')
+ '[' + CAST(#StartNum + number AS varchar) + ']'
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 0 AND 9;
SET #sql =
'WITH numbers AS (
SELECT ' + CAST(#StartNum AS varchar) + ' + number AS N
FROM master..spt_values
WHERE type = ''P''
AND number BETWEEN 0 AND 9
),
products AS (
SELECT
n1.N,
PivotN = n2.N,
P = n1.N * n2.N
FROM numbers n1
CROSS JOIN numbers n2
)
SELECT
N, ' + #NumColumns + '
FROM products
PIVOT (MAX(P) FOR PivotN IN (' + #NumColumns + ')) p';
EXEC(#sql);
Try This:-
DECLARE #InitialValue int =2, #Height int =10, #Width int =10, #ColumnNames varchar(max), #RowNames varchar(max), #sql varchar(max);
SELECT #RowNames = #RowNames + '[' + CAST(#InitialValue + number AS varchar) + ']'
FROM master..spt_values WHERE type = 'P' AND number BETWEEN 0 AND #Height-2
SELECT #ColumnNames = COALESCE(#ColumnNames + ', ', '') + '[' + CAST(#InitialValue + number AS varchar) + ']'
FROM master..spt_values WHERE type = 'P' AND number BETWEEN 0 AND #Width-2
SET #sql =
'WITH numbers AS ( SELECT ' + CAST(#InitialValue AS varchar) + ' + number AS X FROM master..spt_values WHERE type = ''P''
AND number BETWEEN 0 AND ' + CAST(#Height-2 AS varchar) +'
),
products AS (
SELECT n1.X, PivotN = n2.X, P = n1.X * n2.X FROM numbers n1 CROSS JOIN numbers n2
)
SELECT X, ' + #ColumnNames + '
FROM products
PIVOT (MAX(P) FOR PivotN IN (' + #ColumnNames + ')) p'
EXEC(#sql)
-----------------------------------------------------------------------

How do I get a total from a SQL query with a caculated field

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;

Resources