writing a mathematical formula in sql - sql-server

Using the following sql query :
Select count(*) as Totaladmit From v_dbPatientAdmissions where AdmitDate > '2017-01-01' and AdmitDate <'2017-12-30' and PatientType = 2
Select count(*) as TotalDischarge From v_dbPatientAdmissions where DischargeDate > '2017-01-01' and DischargeDate <'2017-012-30' and PatientType = 2
select count(*) as totalIP from v_dbPatientAdmissions where PatientType=2 and DischargeDate is null
select count (BedName) as Bedcount from V_Beds
We get the following output:
TotalAdmit
66668
TotalDischarge
6651
TotalIP
91
BedCount
174
I want to write a mathematical formula that does the following :
In order to crate a crystal report that returns only one value (Rate), also for the Totaladmit and TotalDischarge i want to apply a condition the excludes the records that shares the same AdmitDate and DischargeDate.

As you have different condition on your select, so common group by with WHERE will not work.
You can try like following. This will be the simplest solution.
SELECT ( ( TotalIp + Totaladmit - TotalDischarge ) / BedCount ) * 100 AS
[Output]
FROM (SELECT (SELECT Count(*)
From v_dbPatientAdmissions
where AdmitDate > '2017-01-01'
and AdmitDate < '2017-12-30'
and PatientType = 2) as Totaladmit,
(SELECT Count(*)
From v_dbPatientAdmissions
where DischargeDate > '2017-01-01'
and DischargeDate < '2017-12-30'
and PatientType = 2) as TotalDischarge,
(SELECT Count(*)
from v_dbPatientAdmissions
where PatientType = 2
and DischargeDate is null) as TotalIp,
(SELECT Count (BedName)
from V_Beds) AS Bedcount) T
Apart from this, you can also use CROSS APPLY for doing the same thing.

Please try this-
SELECT
( (
SUM(CASE WHEN PatientType=2 and DischargeDate is null THEN 1 ELSE 0 END) OVER()
+ SUM(CASE WHEN AdmitDate > '2017-01-01' and AdmitDate <'2017-12-30' and PatientType = 2 THEN 1 ELSE 0 END) OVER() )
- (SUM(CASE WHEN DischargeDate > '2017-01-01' and DischargeDate <'2017-012-30' and PatientType = 2 THEN 1 ELSE 0 END) OVER() )
) * 100.0 / ( select COUNT(BedName) OVER() from V_Beds )
FROM v_dbPatientAdmissions

I would bypass the complication of same day discharge by including them in the calculation
for example
drop table t
go
create table t(patientid int, admitdate date, dischargedate date)
create table b(bedname varchar(1))
go
truncate table t
insert into t values (1,'2017-01-01','2017-01-01'),(1,'2017-02-01',null),(2,'2017-01-01','2017-02-01'),
(3,'2016-01-01','2017-01-01'),(4,'2016-01-01',null)
insert into b values ('a'),('b')
select (admittednull + (admitted - discharged - sameday)) / beds * 100 as calulatedratio
from
(
select sum(case when year(admitdate) = 2017 then 1 else 0 end) as admitted,
sum(case when year(dischargedate) = 2017 then 1 else 0 end) as discharged,
sum(case when year(admitdate) <> 2017 and dischargedate is null then 1 else 0 end) as admittednull,
(select count(*) from b) beds,
sum(case when year(admitdate) = 2017 and year(dischargedate) = 2017 and admitdate = dischargedate then 1 else 0 end) sameday
from t
) s
As it happens this returns a value of 0.

Related

MSSQL: calculate time be many starts and stops

Is it possible to make this in sql:
Have table with records:
ID LaborID OrderNr OrderStatusID OrderStatusDate
12990 3731573 OPT1814378 2 2018-05-28 09:35:30.123
13105 230687389 OPT1814378 1 2018-05-29 10:32:14.850
13106 230687389 OPT1814378 2 2018-05-29 10:52:14.403
13123 230480202 OPT1814378 1 2018-05-29 13:18:05.233
13130 230480202 OPT1814378 0 2018-05-29 13:29:17.360
12837 3731573 OPT1814089 2 2018-05-25 20:28:24.817
12906 10138504 OPT1814089 1 2018-05-26 10:41:18.680
12909 10138504 OPT1814089 2 2018-05-26 10:57:40.733
12913 10138504 OPT1814089 1 2018-05-26 11:41:48.387
12920 10138504 OPT1814089 0 2018-05-26 12:15:48.590
where
OrderStatusID
0 - End
1 - Begin
2 - pause
Need calculate working time from begin to pause (1->2) or from begin to end (1->0).
My problem is that there are some conditions that I have to adhere to:
If first record is 2 then ignore
Work begin always with 1
But can have more pause (1->2)
The last work end record everytime with 0
The result in this case will be:
OPT1814378 230687389 00:20:00
OPT1814378 230480202 00:11:12
OPT1814089 10138504 00:16:12
OPT1814089 10138504 00:34:00
Hopefully this is not that ugly.
; with
cte as
(
-- CTE for generating a sequence no
select *, rn = row_number() over (partition by OrderNr
order by OrderStatusDate)
from #table
),
cte2 as
(
-- Clean up invalid any rows and regenerate new sequence no
select ID, LaborID, OrderNr, OrderStatusID, OrderStatusDate,
rn = row_number() over (partition by OrderNr
order by OrderStatusDate)
from cte
where (rn = 1 and OrderStatusID = 1)
or rn >= 2
)
select OrderNr, LaborID,
convert(varchar(10),
dateadd(second,
datediff(second,
min(OrderStatusDate),
max(OrderStatusDate)),
0),
108)
from cte2
group by OrderNr,
LaborID,
(rn - 1) / 2
(rn - 1) / 2 will gives the value 0, 0, 1, 1, 2, 2 etc for grouping the rows two by two.
This one also works
;WITH CTE
AS (
SELECT row_number() OVER ( PARTITION BY ordernr ORDER BY id ) RN ,* FROM test_ti
)
,cte2
AS (
SELECT *
FROM cte c1
WHERE NOT EXISTS (
SELECT *
FROM cte c2
WHERE c1.id = c2.id
AND c2.rn = 1
AND c2.orderstatusid = 2
)
)
SELECT OrderNr
,LaborId
,TimeInterval
FROM ( SELECT DateDiff(MI, TIME, NxtTm) TimeInterval ,*
FROM (
SELECT * ,lead(TIME) OVER ( ORDER BY id ) NxtTm
FROM cte2
) x
WHERE orderstatusid <> 0
) y
WHERE orderstatusid = 1

SQL Server query In clause

I have a SQL Server query which is supposed to select those first week and third week login to our portal but didn't login at second week. My problem is, the query below taking about 15 secs to be loaded. Is there any faster way or any problem on my query ?
select
count(distinct id )
from
table_x
where
g in (319, 329)
and enable = 1
and Date between '2016-01-18' and '2016-01-24' --Third Week
and id in (select distinct id
from table_x
where g in (319, 329)
and enable = 1
and Date between '2016-01-05' and '2016-01-11' --First Week
and id not in (select distinct id
from table_x
where g in (319, 329)
and enable = 1
and Date between '2016-01-11' and '2016-01-17' --Second Week
)
)
Try using conditional aggregates (a single where clause and summing 3 case expressions) instead of multiple passes through the table.
SELECT
COUNT(*)
FROM (
SELECT
user_id
, SUM(CASE WHEN [Date] BETWEEN '2016-01-18' AND '2016-01-24' THEN 1 ELSE 0 END) [ThirdWeek]
, SUM(CASE WHEN [Date] BETWEEN '2016-01-11' AND '2016-01-17' THEN 1 ELSE 0 END) [SecondWeek]
, SUM(CASE WHEN [Date] BETWEEN '2016-01-05' AND '2016-01-11' THEN 1 ELSE 0 END) [FirstWeek]
FROM table_x
WHERE x1.g IN (319, 329)
AND x1.enable = 1
AND x1.[Date] BETWEEN '2016-01-05' AND '2016-01-24'
GROUP BY
user_id
) d
WHERE [FirstWeek] > 0
AND [ThirdWeek] > 0
AND [SecondWeek] = 0
While I would expect the above to be a good option, perhaps use of EXISTS/NOT EXISTS could help, note you do NOT need distinct in the following example.
SELECT
COUNT(DISTINCT user_id)
FROM table_x x1
WHERE x1.g IN (319, 329)
AND x1.enable = 1
AND x1.[Date] BETWEEN '2016-01-18' AND '2016-01-24' --Third Week
AND EXISTS (
SELECT
NULL
FROM table_x
WHERE g IN (319, 329)
AND enable = 1
AND Date BETWEEN '2016-01-05' AND '2016-01-11' --First Week
AND x1.user_id = table_x.user_id
)
AND NOT EXISTS (
SELECT
NULL
FROM table_x
WHERE g IN (319, 329)
AND enable = 1
AND Date BETWEEN '2016-01-11' AND '2016-01-17' --Second Week
AND x1.user_id = table_x.user_id
)
;

how to join table group by count

I have query_1:
select id,
count(case when no01 ='B' then 1 END) +
count(case when no02='B' then 1 END) +
count(case when no03='B' then 1 END) as Count_All
From tabel_a
where date ='20150201'
group by id
and also I have query_2:
select id, COUNT (*) from tabel_b
where ids <> 'T' and idt ='C'
group by id
How can I join query_1 with query_2 via id?
You could try using sub selects. Something like
SELECT *
FROM (
select id,
count(case when no01 ='B' then 1 END) + count(case when no02='B' then 1 END) + count(case when no03='B' then 1 END) as Count_All
From tabel_a
where date ='20150201'
group by id
) a INNER JOIN
(
select id,
COUNT (*) cnt
from tabel_b
where ids <> 'T'
and idt ='C'
group by id
) b ON a.ID = b.ID
Seeing as you specified SQL Server, you could also make use of a Common Table Expression.
Something like
;WITH a AS (
select id,
count(case when no01 ='B' then 1 END) + count(case when no02='B' then 1 END) + count(case when no03='B' then 1 END) as Count_All
From tabel_a
where date ='20150201'
group by id
)
, b as (
select id,
COUNT (*) cnt
from tabel_b
where ids <> 'T'
and idt ='C'
group by id
)
SELECT *
FROm a INNER JOIN
b ON a.ID = b.ID

How to add Totals in SQL

I am trying to get the totals of each month as of YTD (Years to date) Can someone please help me figure out how to integrate this in my query? thank you This is what I have so far.
DECLARE #Year int
set #Year = 2013
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
From tContact a Join tContract b ON a.contact_id = b.contract_id
Group by a.first_name, a.last_name
This is just an example of how you could count up rows that fall under a certain month.
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)
Hopefully this will help you with your query.
Thanks
What I tried to do here is create an upper bound record for each month in tContract then join that back into the query you already had. It is joined on dates that are between the beginning of the year and the current month.
DECLARE #Year int
set #Year = 2013
select Ms.thismonth, count(B.thing_You_are_Totalling) from (
select thisMonth = dateadd(month,datediff(month,0,Funded_date),0)
from tContract
where moid = 2005405
and year(Funded_date) = #Year
group by dateadd(month,datediff(month,0,Funded_date),0)
) Ms
inner join (select * from tContact a inner join tContract ON a.contact_id = tContract.contract_id) B
on B.Funded_date >=dateadd(year,datediff(year,0,B.Funded_date),0) -- beginning of year
and B.Funded_date <= Ms.thisMonth -- this month
where year(B.Funded_date) = #Year -- restrict to only this year
group by thisMonth, first_name, last_name
I don't have your full table definition so there might be some issues (maybe a SqlFiddle is in order)
Not sure if this is what you are asking for.
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
, COUNT(*) TotalCount
, SUM(CASE WHEN MONTH(b.Funded_date) = 1 THEN Amount ELSE NULL END) JanuaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 2 THEN Amount ELSE NULL END) FebruaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 3 THEN Amount ELSE NULL END) MarchAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 4 THEN Amount ELSE NULL END) AprilAmount
From tContact a Join tContract b ON a.contact_id = b.contact_id
WHERE YEAR(b.Funded_date) = #Year
Group by a.first_name, a.last_name
How about this:
declare #year int = 2013
select a.first_name
, a.last_name
, month(b.Funded_date) [Month]
, datename(month, dateadd(month, month(date_of_birth_dt), - 1)) [MonthName]
, count(month(b.Funded_date)) [Total]
from tContact a
where a.[Year] = #year
group by a.first_name, a.last_name, month(b.Funded_date)
It returns the total of each Month for the year 2013. a.[Year] might not the the name of the field that you have so adjust accordingly. Also, [Month] returns numeric value for month.
Use the Count(*) As Total function. I'm sure this will help you
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)

create a statistics table using datetime MSSQL Query

I have little table which gives me a very hard time:
Person datetime1 datetime2
Eric 2012-10-01 09:00:05.000 2012-10-01 22:00:00.000
Anna 2012-10-02 06:00:05.000 2012-10-03 12:00:05.000
Richard 2012-10-03 09:00:05.000 2012-10-04 02:00:05.000
Chuck 2012-10-01 12:00:05.000 2012-10-01 23:00:05.000
I am trying to write a query, which gives me statistics table. This table contains information about when a user logged in and out (daily granularity):
Date logged_in logged_off
2012-10-01 2 2
2012-10-02 1 0
2012-10-03 1 1
2012-10-04 0 1
According to my research, a pivot command could solve the problem?
select Person,
SUM(case when datetime1 = '2012-10-01' then 1 else 0 end) as [loggeed_in],
SUM(case when datetime2 = '2012-10-01' then 1 else 0 end) as [logged_of]
from table
group by Person
This is not working... Do you have any ideas?
This will fix the current query, but don't know if it will solve the whole problem...
select Person,
SUM(case when convert(varchar(10), datetime1, 111) = '2012/10/01' then 1 else 0 end) as [loggeed_in],
SUM(case when convert(varchar(10), datetime2, 111) = '2012/10/01' then 1 else 0 end) as [logged_of]
from table
group by Person
EDIT: I believe this will better suit requirements...
SELECT
[Date] = dt,
logged_in = (
SELECT COUNT(*)
FROM table1
WHERE convert(varchar(10), datetime1, 111) = convert(varchar(10), dt, 111)),
logged_off = (
SELECT COUNT(*)
FROM table1
WHERE convert(varchar(10), datetime2, 111) = convert(varchar(10), dt, 111))
FROM (
SELECT TOP 1000
row_number() OVER(ORDER BY (SELECT 0)) AS N
FROM master.dbo.syscolumns sc1, master.dbo.syscolumns sc2) tally
CROSS APPLY(
SELECT dt = DATEADD(dd, tally.N - 1, '2012-10-1')) tallydt
WHERE dt BETWEEN (SELECT MIN(dateadd(dd, -1, datetime1)) FROM table1) AND (SELECT MAX(datetime2) FROM table1)
GROUP BY dt
ORDER BY dt
Here is the working solution:
WITH O AS (
SELECT
CAST([login Date & Time] AS DATE) loginDate
,COUNT(*) logined
FROM table
GROUP BY CAST([login Date & Time] AS DATE)
), C AS (
SELECT
CAST([Close Date & Time] AS DATE) CloseDate
,COUNT(*) Closed
FROM table
WHERE [Close Date & Time] IS NOT NULL
GROUP BY CAST([Close Date & Time] AS DATE)
)
SELECT
COALESCE(C.CloseDate, O.loginDate) TheDate
--,O.loginDate
--,C.CloseDate
,O.logined
,C.Closed
FROM O
FULL JOIN C
ON O.loginDate = C.CloseDate
ORDER BY TheDate

Resources