Excluding First and last rows from a sum window function in SQL - sum

I am executing the following query
SELECT QLID,
Emp_Date,
Emp_Time,
sum(emp_time) over(partition by qlid order by emp_time)
FROM GCC_INTERNAL_OPS.Entry_Time
where (qlid='fs255015' or qlid='mf255005')
and emp_date=date '2013-01-31'
which returns the following resultset
QLID Emp_Date Emp_Time Group Sum(Emp_Time)
FS255015 01/31/2013 1218 5390.00
FS255015 01/31/2013 1523 5390.00
FS255015 01/31/2013 1526 5390.00
FS255015 01/31/2013 1123 5390.00
MF255005 01/31/2013 0932 15033.00
MF255005 01/31/2013 0936 15033.00
MF255005 01/31/2013 1106 15033.00
MF255005 01/31/2013 1332 15033.00
MF255005 01/31/2013 1338 15033.00
MF255005 01/31/2013 1348 15033.00
MF255005 01/31/2013 1509 15033.00
MF255005 01/31/2013 1544 15033.00
MF255005 01/31/2013 1617 15033.00
MF255005 01/31/2013 1639 15033.00
MF255005 01/31/2013 1732 15033.00
I want to exclude the first and last row in summation for each qlid. Any thoughts on how will I do that?

Try:
;with cte as
(SELECT e.*,
row_number() over(partition by qlid order by emp_time) rna,
row_number() over(partition by qlid order by emp_time desc) rnd
FROM Entry_Time e
where (qlid='fs255015' or qlid='mf255005') and emp_date='2013-01-31')
SELECT QLID,
Emp_Date,
Emp_Time,
sum(case when 1 in (rna,rnd) then 0 else emp_time end)
over(partition by qlid) conditional_sum
FROM cte
SQLFiddle here.

Related

SQL : GROUP and MAX multiple columns

I am a SQL beginner, can anyone please help me about a SQL query?
my table looks like below
PatientID Date Time Temperature
1 1/10/2020 9:15 36.2
1 1/10/2020 20:00 36.5
1 2/10/2020 8:15 36.1
1 2/10/2020 18:20 36.3
2 1/10/2020 9:15 36.7
2 1/10/2020 20:00 37.5
2 2/10/2020 8:15 37.1
2 2/10/2020 18:20 37.6
3 1/10/2020 8:15 36.2
3 2/10/2020 18:20 36.3
How can I get each patient everyday's max temperature:
PatientID Date Temperature
1 1/10/2020 36.5
1 2/10/2020 36.3
2 1/10/2020 37.5
2 2/10/2020 37.6
Thanks in advance!
For this dataset, simple aggregation seems sufficient:
select patientid, date, max(temperature) temperature
from mytable
group by patientid, date
On the other hand, if there are other columns that you want to display on the row that has the maximum daily temperature, then it is different. You need some filtering; one option uses window functions:
select *
from (
select t.*,
rank() over(partition by patientid, date order by temperature desc)
from mytable t
) t
where rn = 1

Multiple Rows to one row

I have one tricky problem. (At least for me) I need to get all the values for the rows with the same AdressNrADR on one row instead of multiple. Is their some way to do this?
SELECT ADR_Adressen.AdressNrADR, CRM_Aufgaben.TerminVon, LAG_Artikel.ArtikelNrLAG,
PRO_Auftraege.Z_R_ckmeldung_Zusatzartikel, CRM_AufgabenLink.MitNrPRO FROM ( ( ( ( ( ( ADR_Adressen
LEFT JOIN PRO_Auftraege ON ADR_Adressen.AdressNrADR = PRO_Auftraege.Kunde)
LEFT JOIN CRM_Aufgaben ON PRO_Auftraege.AuftragNrPRO = CRM_Aufgaben.AuftragNrPRO)
LEFT JOIN CRM_Status ON CRM_Aufgaben.StatusCRM = CRM_Status.StatusCRM)
LEFT JOIN LAG_Artikel ON CRM_Aufgaben.ArtikelNrLAG = LAG_Artikel.ArtikelNrLAG)
LEFT JOIN ADR_GruppenLink ON ADR_Adressen.AdressNrADR = ADR_GruppenLink.AdressNrADR)
LEFT JOIN ADR_Gruppen ON ADR_GruppenLink.GruppeADR = ADR_Gruppen.GruppeADR)
LEFT JOIN CRM_AufgabenLink ON CRM_Aufgaben.AufgabenNrCRM = CRM_AufgabenLink.AufgabenNrCRM
WHERE { d '2020-02-10'}<=CRM_Aufgaben.TerminVon AND { d '2020-02-16'}+1>=CRM_Aufgaben.TerminBis and CRM_AufgabenLink.MitNrPRO != 0 and CRM_Status.StatusCRM = 1 GROUP BY ADR_Adressen.AdressNrADR,CRM_Aufgaben.TerminVon,CRM_Aufgaben.TerminBis, ADR_Adressen.Name, ADR_Adressen.Vorname, LAG_Artikel.ArtikelNrLAG, LAG_Artikel.Bezeichnung1,CRM_AufgabenLink.MitNrPRO,PRO_Auftraege.Z_R_ckmeldung_Zusatzartikel
ORDER BY ADR_Adressen.Name
Output now:
AdressNrADR TerminVon ArtikelNrLAG Z_R_ckmeldung_Zusatzartikel MitNrPRO
13507 2020-02-12 11:00:00.000 7601 7602 2169
13507 2020-02-13 15:00:00.000 7311 NULL 2337
13507 2020-02-14 10:00:00.000 7311 NULL 1028
12955 2020-02-11 08:00:00.000 7311 NULL 1028
12955 2020-02-11 14:00:00.000 3101 NULL 2347
12955 2020-02-13 10:00:00.000 7311 7352 1991
12955 2020-02-13 13:00:00.000 3101 NULL 2347
12955 2020-02-13 14:00:00.000 7311 NULL 1028
10007 2020-02-11 15:00:00.000 7601 7602 1806
10007 2020-02-14 13:00:00.000 7311 NULL 1833
Desired Output:
AdressNrADR TerminVon1 ArtikelNrLAG1 Z_R_ckmeldung_Zusatzartikel1 MitNrPRO1 TerminVon2 ArtikelNrLAG2 Z_R_ckmeldung_Zusatzartikel2 MitNrPRO2 TerminVon3 ArtikelNrLAG3 Z_R_ckmeldung_Zusatzartikel3 MitNrPRO3
13507 2020-02-12 11:00:00.000 7601 7602 2169 2020-02-13 15:00:00.000 7311 NULL 2337 2020-02-14 10:00:00.000 7311 NULL 1028
You can use conditional aggregation and row_number():
with cte as (
<your query here>
)
select AdressNrADR,
max(case when seqnum = 1 then TerminVon end) as TerminVon1,
max(case when seqnum = 1 then ArtikelNrLAG end) as ArtikelNrLAG1,
. . .
max(case when seqnum = 2 then TerminVon end) as TerminVon2,
. . .
from (select cte.*, row_number() over (partition by AdressNrADR order by AdressNrADR) as seqnum
from cte
) t
group by AdressNrADR;

Attendance Log using MS Access or SQL Server

I'm working this almost a month but I think I need some help now. I have a time logs below. I'm using MS Access and C#. Please help what select query
ID BADGE CHECKTIME
-----------------------------
1 1507010 5/31/2018 8:51
1 1507010 5/31/2018 19:52
2 1708004 5/31/2018 6:35
2 1708004 5/31/2018 13:43
3 1708005 5/31/2018 19:23
3 1708005 6/1/2018 8:34
4 1708006 5/31/2018 7:51
4 1708006 6/1/2018 18:34
5 1708007 5/31/2018 19:23
5 1708007 6/1/2018 6:36
6 1708009 5/31/2018 7:11
6 1708009 5/31/2018 7:12
6 1708009 5/31/2018 22:02
6 1708009 5/31/2018 22:03
I want to become this.please help. what the best query to get this data.
ID Badge IN OUT
--------------------------------------------
1 1507010 5/31/2018 8:51 5/31/2018 13:43
2 1708004 5/31/2018 6:35 5/31/2018 13:43
3 1708005 5/31/2018 19:23 6/1/2018 8:34
4 1708006 5/31/2018 7:51 6/1/2018 18:34
5 1708007 5/31/2018 19:23 6/1/2018 6:36
6 1708009 5/31/2018 7:12 5/31/2018 22:03
The following query should get close to what you want:
SELECT
ID,
Badge,
MIN(CHECKTIME) AS [IN],
MAX(CHECKTIME) AS [OUT]
FROM yourTable
GROUP BY
ID,
Badge;
I have a doubt about your expected output for badge 1708009, since the earliest check time for that badge is 7:11, not 7:12.
I would use row_number() inside the subquery :
select id, badge, min(checktime) as in, max(checktime) as out
from (select *, row_number() over (partition by id, badge, cast(checktime as date), datepart(hh,checktime)
order by datepart(mm,checktime) desc) seq
from table
) t
where seq = 1
group by id, badge;

SQL - Group By based on sequence - Oracle/Postgre

I need some help.
To perform a group by based on a sequence.
I'm using Oracle or Postgres.
I have the following scenario. The ID_SEQ is based on equip_id, Day and Stat. Creating a sequence.
I need to group the intervals between these sequences.
Example:
EQUIP_ID DAY STAT DATE ID_SEQ
JSTD123 19/06/2017 ON 19/06/2017 16:39 1
JSTD123 19/06/2017 OFF 19/06/2017 16:41 1
JSTD123 01/07/2017 ON 01/07/2017 13:50 1
JSTD123 01/07/2017 OFF 01/07/2017 13:51 1
JSTD123 01/07/2017 OFF 01/07/2017 14:40 2
JSTD123 01/07/2017 ON 01/07/2017 15:20 1
JSTD123 01/07/2017 ON 01/07/2017 15:20 2
JSTD123 01/07/2017 ON 01/07/2017 15:22 3
JSTD123 01/07/2017 ON 01/07/2017 15:22 4
JSTD123 01/07/2017 ON 01/07/2017 15:23 5
JSTD123 01/07/2017 ON 01/07/2017 15:26 6
JSTD123 01/07/2017 ON 01/07/2017 15:26 7
I would like to have the following result:
EQUIP_ID DATE STAT START END
JSTD123 19/06/2017 ON 19/06/2017 16:39 19/06/2017 16:39
JSTD123 19/06/2017 OFF 19/06/2017 16:41 19/06/2017 16:41
JSTD123 01/07/2017 ON 01/07/2017 13:50 01/07/2017 13:50
JSTD123 01/07/2017 OFF 01/07/2017 13:51 01/07/2017 14:40
JSTD123 01/07/2017 ON 01/07/2017 15:20 01/07/2017 15:26
I can't get a similar output.
I think this is what you are trying to do. Grouping consecutive rows with the same stat on a given day and getting the min date and max date of that group.
The logic is to assign groups by getting the previous value of stat (per equip_id and day) using lag and then using a running sum to reset when a new stat value is encountered. After this group assignment is done, you can just use group by to get the min and max date per equip_id,stat,day and grp.
SELECT equip_id,
day,
stat,
min(date),
max(date)
FROM
(SELECT t.*,
sum(col) over(partition BY equip_id,day ORDER BY date) AS grp
FROM
(SELECT t.*,
CASE WHEN stat=lag(stat) over(partition BY equip_id,day ORDER BY date) THEN 0 ELSE 1 END AS col
FROM t
) t
) t
GROUP BY equip_id,day,stat,grp
Sample Demo

How to select most recent values?

I have a logging table collecting values from many probes:
CREATE TABLE [Log]
(
[LogID] int IDENTITY (1, 1) NOT NULL,
[Minute] datetime NOT NULL,
[ProbeID] int NOT NULL DEFAULT 0,
[Value] FLOAT(24) NOT NULL DEFAULT 0.0,
CONSTRAINT Log_PK PRIMARY KEY([LogID])
)
GO
CREATE INDEX [Minute_ProbeID_Value] ON [Log]([Minute], [ProbeID], [Value])
GO
Typically, each probe generates a value every minute or so. Some example output:
LogID Minute ProbeID Value
====== ================ ======= =====
873875 2014-07-27 09:36 1972 24.4
873876 2014-07-27 09:36 2001 29.7
873877 2014-07-27 09:36 3781 19.8
873878 2014-07-27 09:36 1963 25.6
873879 2014-07-27 09:36 2002 22.9
873880 2014-07-27 09:36 1959 -30.1
873881 2014-07-27 09:36 2005 20.7
873882 2014-07-27 09:36 1234 23.8
873883 2014-07-27 09:36 1970 19.9
873884 2014-07-27 09:36 1991 22.4
873885 2014-07-27 09:37 1958 1.7
873886 2014-07-27 09:37 1962 21.3
873887 2014-07-27 09:37 1020 23.1
873888 2014-07-27 09:38 1972 24.1
873889 2014-07-27 09:38 3781 20.1
873890 2014-07-27 09:38 2001 30
873891 2014-07-27 09:38 2002 23.4
873892 2014-07-27 09:38 1963 26
873893 2014-07-27 09:38 2005 20.8
873894 2014-07-27 09:38 1234 23.7
873895 2014-07-27 09:38 1970 19.8
873896 2014-07-27 09:38 1991 22.7
873897 2014-07-27 09:39 1958 1.4
873898 2014-07-27 09:39 1962 22.1
873899 2014-07-27 09:39 1020 23.1
What is the most efficient way to get just the latest reading for each Probe?
e.g.of desired output (note: the "Value" is not e.g. a Max() or an Avg()):
LogID Minute ProbeID Value
====== ================= ======= =====
873899 27-Jul-2014 09:39 1020 3.1
873894 27-Jul-2014 09:38 1234 23.7
873897 27-Jul-2014 09:39 1958 1.4
873880 27-Jul-2014 09:36 1959 -30.1
873898 27-Jul-2014 09:39 1962 22.1
873892 27-Jul-2014 09:38 1963 26
873895 27-Jul-2014 09:38 1970 19.8
873888 27-Jul-2014 09:38 1972 24.1
873896 27-Jul-2014 09:38 1991 22.7
873890 27-Jul-2014 09:38 2001 30
873891 27-Jul-2014 09:38 2002 23.4
873893 27-Jul-2014 09:38 2005 20.8
873889 27-Jul-2014 09:38 3781 20.1
This is another approach
select *
from log l
where minute =
(select max(x.minute) from log x where x.probeid = l.probeid)
You can compare the execution plan w/ a fiddle - http://sqlfiddle.com/#!3/1d3ff/3/0
Try this:
SELECT T1.*
FROM Log T1
INNER JOIN (SELECT Max(Minute) Minute,
ProbeID
FROM Log
GROUP BY ProbeID)T2
ON T1.ProbeID = T2.ProbeID
AND T1.Minute = T2.Minute
You can play around with it on SQL Fiddle
Your question is: "What is the most efficient way to get just the latest reading for each Probe?"
To really answer this question, you test to test different solutions. I would generally go with the row_number() method suggested by #jyparask. However, the following might have better performance:
select l.*
from log l
where not exists (select 1
from log l2
where l2.probeid = l.probeid and
l2.minute > l.minute
);
For performance, you want an index on log(probeid, minute).
Although not exactly your problem, here is an example of where not exists performs better than other methods on SQL Server.
;WITH MyCTE AS
(
SELECT LogID,
Minute,
ProbeID,
Value,
ROW_NUMBER() OVER(PARTITION BY ProbeID ORDER BY Minute DESC) AS rn
FROM LOG
)
SELECT LogID,
Minute,
ProbeID,
Value
FROM MyCTE
WHERE rn = 1