SQL Grouping and Counting based on dates - sql-server

Getting nowhere here and seems so simple.
Test data is:
declare #table table(SpellAdminsionDate datetime, SpellDischargeDate datetime, Pat_code varchar(10))
insert into #table (SpellAdminsionDate, SpellDischargeDate, Pat_code) values('2016-09-12 15:55:00:000','2016-09-19 20:20:00:000','HEY3052275')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-09-07 17:17:00:000','2016-09-17 18:40:00:000','HEY0810155')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-09-14 16:50:00:000','2016-09-17 18:01:00:000','HEY1059266')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-09-15 02:47:00:000','2016-09-15 17:28:00:000','HEY0742883')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-08-27 00:11:00:000','2016-09-14 12:49:00:000','HEY3050628')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-09-10 12:24:00:000','2016-09-13 20:00:00:000','HEY0912392')
insert into #table(SpellAdminsionDate, SpellDischargeDate, Pat_code) values ('2016-09-12 12:51:00:000','2016-09-13 19:55:00:000','HEY0908691')
Select * from #table`
Below is my simple code displaying the same thing:
SELECT c.SpellAdmissionDate,
c.SpellDischargeDate,
c.Pat_Code
FROM [CommDB].[dbo].[vwCivicaSLAM1617Live] c
WHERE c.Hrg_Code like 'VA%'
and c.Pat_Code like 'HEY%'
ORDER BY c.SpellDischargeDate desc
All I am after is a COUNT per day of active patients, for example take the 12/09/2016 on that date the result would be 5 (based on the test data) as the other 2 cam in after the 12th.
If it makes it easier I do have a date reference table called DATE_REFERENCE which has every date available to me.

Allowing for the possibility of having no patients on a day then you want to use your date reference table as the primary and left join to the patient information. You don't identify a column name so I just used [datecol].
SELECT
d.[datecol] the_date
, count(DISTINCT c.Pat_Code) num_patients
FROM DATE_REFERENCE d
LEFT JOIN [CommDB].[dbo].[vwCivicaSLAM1617Live] c
ON d.[datecol] BETWEEN c.SpellAdmissionDate AND c.SpellDischargeDate
AND c.Hrg_Code LIKE 'VA%'
AND c.Pat_Code LIKE 'HEY%'
GROUP BY
d.[datecol]
ORDER BY
d.[datecol] DESC
I suspect there may be more than this required, but without sample data and expected results it is difficult to know what you really need.
nb. I assume the date in that date_reference table is at midnight (00:00:00) or has a data type of date (without hours/minutes etc.)

Is this what you want?
SELECT dr.date,
(SELECT COUNT(*)
FROM [CommDB].[dbo].[vwCivicaSLAM1617Live] c
WHERE dr.date between c.SpellAdmissionDate and c.SpellDischargeDate) as cnt_per_day
FROM DATE_REFERENCE dr
Add the filters you want to the correlated query .

You can achieve this by joining to your date reference table and counting by a distinct of the patient reference
SELECT
dateRef
,COUNT(DISTINCT Pat_Code) AS PatCount
FROM #table t
RIGHT JOIN #date_reference
ON SpellAdminsionDate <= dateRef
AND SpellDischargeDate >= dateRef
GROUP BY dateRef;

Active count of patients per date can be achieved by (for temp data provided here)
SELECT DISTINCT CAST(T1.SPELLADMINSIONDATE AS DATE)
AdmissionDate,PATIENTS.TotalActive
FROM #TABLE T1
CROSS APPLY (SELECT COUNT(*)TotalActive FROM #TABLE T2 WHERE
CAST(T2.SPELLADMINSIONDATE AS DATE)<=CAST(T1.SPELLADMINSIONDATE AS DATE)) PATIENTS

I think you need to bring the DATE_REFERENCE table to the Query If it contains all the day dates that you need to count patients based on them, But here is a sample of how may you get the required result form this table only
Select DISTINCT c.SpellAdmissionDate, count(c.Pat_code) as PCounter
From [CommDB].[dbo].[vwCivicaSLAM1617Live] c
GROUP BY c.SpellAdmissionDate
ORDER BY c.SpellAdmissionDate desc

Related

Calculation of Average of distinct values

I have date in below format:
Now, I am want to display latest Post Date of each Account No, its corresponding amount, average of Amount of all previous dates including the latest date but the hack is I need to display latest Post Date based on ShareID.
I need the Amount of minimum ShareID and while taking average I have to omit amount of duplicate/same date of max(Postdate).
I need the data in below format:
You can try :
WITH
T1 AS
(
SELECT AccountNo, FundNo, MAX(PostDate) AS LastPostDate
FROM MyTable
GROUP BY AccountNo, FundNo,
),
T2 AS
(
SELECT DISTINCT AccountNo, FundNo, Amount
FROM MyTable
)
SELECT T1.AccountNo, T1.FundNo, T1.LastPostDate, T.PostDate, AVG(T2.Amount)
FROM T1
JOIN T2 ON T1.AccountNo = T2.AccountNo
JOIN MyTable AS T ON T.AccountNo = T1.AccountNo AND T.PostDate, = T1.LastPostDate
Post the DDL of your table and an example under a INSERT SQL statements to help us sto give a correct solution please.

dynamic SQL - Allocate count of midnights to correct month

This is a fairly common issue that I've seen a lot of people duck tape together solutions for, but it's never quite right. Hoping this forum can get it ironed out. I have a table:
create table temp
( PatientID varchar(12),
AdmitDate datetime,
DischargeDate datetime
)
insert into temp values ('Patient1','1/30/2020 13:23:44', '2/2/2020 15:12:52')
What I'd like to count is the number of midnights the patient was admitted in the correct month. So in the example above the patient would be admitted at midnight on 1/31, 2/1, and 2/2 dates. So my output in sql should look something like:
01-2020 02-2020
------- --------
1 2
I know it has to be dynamic SQL, because the columns need to be created with respect to the date range queried. Although, I'm pretty stumped as to next steps.
create table #temp
( PatientID varchar(12),
AdmitDate datetime,
DischargeDate datetime
)
insert into #temp values ('Patient1','1/30/2020 13:23:44', '2/2/2020 15:12:52')
--Virtually creates a dates table
;with dates(thedate) as (
select dateadd(yy,years.number,0)+days.number
from master..spt_values years
join master..spt_values days
on days.type='P' and days.number < datepart(dy,dateadd(yy,years.number+1,0)-1)
where years.type='P' and years.number between 100 and 150
-- note: 100-150 creates dates in the year range 2000-2050
-- adjust as required
)
select dateadd(m,datediff(m, 0, d.thedate),0) [Month], count(1) PatientDays
from dates d
join #temp t on d.thedate between t.[AdmitDate] and t.[DischargeDate]
group by datediff(m, 0, d.thedate)
order by [Month];

Finding the Median value from a table, Group By Date SQLServer

I have a complicated problem I am trying to solve. Please bear with me and feel free to ask any questions. I am quite new to SQL and having difficulty with this...
I need to count the median of a group of values. Now the values are not given in a table. The values are derived from a table based on hourly occurrences grouped by date.
Here's the sample table from where data is pooled.
CREATE TABLE Table22(
Request_Number BIGINT NOT NULL
,Request_Received_Date DATETIME NOT NULL
);
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016311446,'8/9/16 9:56');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20163612157,'9/6/16 9:17');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016384250,'9/12/16 14:52');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20162920101,'4/19/16 8:11');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016418170,'10/6/16 12:28');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016392953,'9/6/16 12:39');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20164123416,'10/6/16 15:05');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016335972,'8/9/16 7:49');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20162622951,'9/6/16 9:57');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20163913504,'9/6/16 9:47');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20163211326,'9/6/16 12:38');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20163610132,'8/30/16 16:34');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20164119560,'10/6/16 15:53');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016334416,'8/10/16 11:06');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20164320028,'10/6/16 15:27');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (20163515193,'8/24/16 19:50');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016159834,'4/19/16 13:21');
INSERT INTO Table22(Request_Number,Request_Received_Date) VALUES (2016178443,'4/19/16 13:05');
The Table has 2 columns: Request_Number and Request_Received_Date.
Request_Number is not unique and is kind of irrelevant. I am looking for how many requests are received for a particular date and hourly within that date (24 hours). Every time there is an entry for a date, that is counted as one occurrence (TicketCount). I can use the COUNT statements to count * from Request_received_date and group by date and hour.
I did just that and created a temporary table within my script:
CREATE TABLE #z (ForDate date, OnHour int, TicketCount int)
INSERT INTO #z (ForDate, OnHour, TicketCount)
SELECT CAST(Request_received_date as DATE) AS 'ForDate',
DATEPART(hh, request_received_date) AS 'OnHour',
COUNT(*) AS TicketCount /*Hourly Ticket Count Column*/
FROM Table22
GROUP BY CAST(request_received_date as DATE), DATEPART(hh, request_received_date)
ORDER BY ForDate Desc, OnHour ASC
SELECT * FROM #z order by ForDate Desc, OnHour ASC
Now I am having the hardest time finding the median value of count per day. I have tried many different formula for median calculation and was able to make most them work. Many different examples of median calculation can be found here
https://sqlperformance.com/2012/08/t-sql-queries/median
I like this piece of script to find median. The script for finding median is simple. But it finds median for all the values of Request_Received_Date. I am unable to find a way to use the group by date clause in here.
DECLARE #Median DECIMAL (12,2);
SELECT #Median = (
(SELECT MAX(TicketCount) FROM
(SELECT TOP 50 PERCENT TicketCount FROM #z ORDER BY TicketCount) AS BottomHalf)
+
(SELECT MIN(TicketCount) FROM
(SELECT TOP 50 PERCENT TicketCount FROM #z ORDER BY TicketCount DESC) AS TopHalf))/2;
SELECT #Median
Any help will be really appreciated.
The expected result is something like this:
ForDate Median
10/6/2016 2
9/12/2016 1
9/6/2016 2.5
8/30/2016 1
8/24/2016 1
8/10/2016 1
8/9/2016 1
4/19/2016 1.5
How about something like this? (Only apply if you use SQL Server 2012 or above)
SELECT DISTINCT ForDate, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY TicketCount) OVER (PARTITION BY ForDate) AS Median
FROM #z;
In short, SQL-Server has two ways to calculate median, you can read about it here: https://msdn.microsoft.com/en-us/library/hh231327.aspx
You can compare them both in this case with the code here:
SELECT DISTINCT
ForDate
, PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY TicketCount) OVER (PARTITION BY ForDate) AS MedianDisc
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY TicketCount) OVER (PARTITION BY ForDate) AS MedianCont
FROM
#z;

Best approach to merge three distinct TSQL select statments

I'm looking to return one tsql statement, that contains four fields, from three separate, unrelated tables.
One table contains a list of objects, say fruits, and for each fruit, I want a sell buy date and best before date.
First statement would therefore look something like:
select fruit from fruit table -- this returns multiple rows
Second statement would look something like:
select sellbuyDate from sellTable -- this returns a single row
and the third would look something like:
select bestbefore from bestTable -- this returns a single row
Don't get to hung up on the table names. I'm working on a legacy system, that we cant change, so need to combine the three table into one.
The underlining table needs to have all the fields returned in a single row, with the second and third results applied to the first statement.
Apples | 12-12-2008 | 12-12-2009
Pears | 12-12-2008 | 12-12-2009
I've implemented the following temp table:
CREATE TABLE #Fruits
(
Fruit VARCHAR(100),
SellBuyDate DATETIME,
BestBefore DATETIME
)
INSERT INTO #Fruits
SELECT Fruit from fruit
INSERT INTO #Fruits
SELECT sellbuyDate from sellTable
INSERT INTO #Fruits
SELECT bestbefore from bestable
SELECT * from #Fruits
This throws an error, because each insert doesn't contain the three fields specified.
any other suggestions would be well received.
You can select them all together by doing a CROSS JOIN by not specifying any join criteria between the three tables as follows:
CREATE TABLE fruit ( fruit_name VARCHAR(30) );
CREATE TABLE sellTable ( sellByDate DATETIME );
CREATE TABLE bestTable ( bestBefore DATETIME );
CREATE TABLE allFruits
(
fruit_name VARCHAR(30),
sellByDate DATETIME,
bestBefore DATETIME
);
INSERT INTO fruit (fruit_name)
VALUES ('apple'), ('pear');
INSERT INTO sellTable(sellByDate)
VALUES ('12/05/2012');
INSERT INTO bestTable(bestBefore)
VALUES ('12/12/2012');
INSERT INTO allFruits (fruit_name, bestBefore, sellByDate)
SELECT f.fruit_name, b.bestBefore, s.sellByDate
FROM fruit f, bestTable b, sellTable s;
SELECT *
FROM allFruits;
maybe you are looking for this answer, although your question could be a little clearer on what that would accomplish
INSERT INTO #Fruits(fruit)
SELECT Fruit from fruit
INSERT INTO #Fruits(sellbuyDate)
SELECT sellbuyDate from sellTable
INSERT INTO #Fruits(bestbefore)
SELECT bestbefore from bestable
SELECT * from #Fruits
the other possible solution is
insert into #Fruits
select Fruit, sellbuyDate, bestbefore from fruit
cross join sellTable
cross join bestable
May be you need this.
SELECT FRUIT,
(SELECT SELLBUYDATE FROM SELLTABLE) AS SELLBUYDATE,
(SELECT BESTBEFORE FROM BESTTABLE) AS BESTBEFORE
FROM FRUIT
or
SELECT FRUIT.FRUIT
, SELLTABLE.SELLBUYDATE
, BESTTABLE.BESTBEFORE
FROM FRUIT
INNER JOIN SELLTABLE ON 1=1
INNER JOIN BESTTABLE ON 1=1
Without the schema of the 3 tables. I would guess its one of the following.
CREATE TABLE #Fruits
(
Fruit VARCHAR(100),
SellBuyDate DATETIME,
BestBefore DATETIME
)
INSERT INTO #Fruits(Fruit,SellBuyDate,BestBefore)
Select Fruit, Sellbuydate,bestbefore
from fruit,selltable,bestable
Or if your tables are set up properly
INSERT INTO #Fruits(Fruit,SellBuyDate,BestBefore)
Select Fruit, Sellbuydate,bestbefore
from fruit f
inner join selltable s
on f.pkey = s.fkey
inner join bestable b
on f.pkey = b.fkey

How do I join two tables on a common column name where 1 table has multiple rows of text I need to concatinate?

I'm trying to return one row result on a.OrderNumber = b.OrderNumber where table b has multiple lines of service comments. Will I need to concatenate the comments into one field result to prevent multiple rows and how do I do that? Here is what I have.
SELECT a.OrderNumber,
b.Comment,
b.Comment,
b.DATE
FROM Orders a
LEFT JOIN Comments b ON a.OrderNumber = b.OrderNumber
I'm looking for:
OrderNumber Comment
1200 01-01-13 Repair made, 01-02-13 Billed Customer
What I get is:
OrderNumber Comment Date
1200 Repair made 01-01-13
1200 Billed Customer 01-02-13
Here's the result I currently have:
Since the OP seemed to have difficulty with the provided code sample I have updated the answer to include the full code result seeing as how the question now includes enough information to make an approximation of the underlying schema.
Incidentally, try not to use reserved words as column names.
CREATE TABLE Orders (OrderNumber INT);
GO
CREATE TABLE Comments (OrderNumber INT, Comment VARCHAR(255), CommentDate DATETIME);
GO
INSERT INTO Orders VALUES (1),(2);
INSERT INTO Comments VALUES
(1, 'Stuff', GETDATE()),
(1, 'Other Stuff', GETDATE()),
(2, 'More stuff', GETDATE())
;WITH cteOrderComment AS (
SELECT a.OrderNumber
,STUFF((
SELECT CONVERT(VARCHAR, C.CommentDate, 10) + ' ' + Comment + ', '
FROM Comments C
WHERE C.OrderNumber = A.OrderNumber
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Comments]
FROM Orders a
GROUP BY a.OrderNumber
)
SELECT T.OrderNumber, LEFT(T.Comments, LEN(T.Comments) - 1) [Comments]
FROM cteOrderComment T
GO
DROP TABLE Orders
DROP TABLE Comments

Resources