Attendance Log using MS Access or SQL Server - sql

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;

Related

How to do complex order by in SQL Server

I am trying to do a complex order by or possibly a group by and then order by. The table name is curtomer_updates. What I want it to do is first of all sort by descending order on the last_updated_date and then have a unique cust_id together sorted by last_updated_date. Below is an example of what it is right now and the expected result. Thank you for any help.
Table normally sorted
Update_ID
Cust_Id
Field_updated
Last_updated_date
Updated_by
1
1223
Name
2021-11-01 12:23
Frodo Baggins
2
9999
address
2021-12-02 19:23
Legolas
3
2200
phone
2021-12-03 23:00
Bilbo Baggins
4
2200
Name
2022-01-04 02:23
Bilbo Baggins
5
9999
phone
2022-02-05 12:23
Golum
6
9999
address
2022-03-06 20:00
Sauron
7
1223
address
2022-04-07 01:24
Gandalf
8
2200
email
2022-05-08 12:50
Some Urkai
9
3412
email, phone
2022-06-08 08:45
Golum
10
1223
address
2022-07-10 00:23
Pippin
11
3412
email, address
2022-09-22 16:48
Gandalf
Expected result
Update_ID
Cust_Id
Field_updated
Last_updated_date
Updated_by
11
3412
email, address
2022-09-22 16:48
Gandalf
9
3412
email, phone
2022-06-08 08:45
Golum
10
1223
address
2022-07-10 00:23
Pippin
7
1223
address
2022-04-07 01:24
Gandalf
1
1223
Name
2021-11-01 12:23
Frodo Baggins
8
2200
email
2022-05-08 12:50
Some Urkai
4
2200
Name
2022-01-04 02:23
Bilbo Baggins
3
2200
phone
2021-12-03 23:00
Bilbo Baggins
6
9999
address
2022-03-06 20:00
Sauron
5
9999
phone
2022-02-05 12:23
Golum
2
9999
address
2021-12-02 19:23
Legolas
SELECT *
FROM curtomer_updates
ORDER BY
MAX(Last_updated_date) OVER (PARTITION BY cust_id) DESC
,Last_updated_date DESC
using sample set:
SELECT *
FROM ( VALUES
(1,1223, 'Name', '2021-11-01 12:23', 'Frodo Baggins'),
(2,9999, 'address', '2021-12-02 19:23', 'Legolas'),
(3,2200, 'phone', '2021-12-03 23:00', 'Bilbo Baggins'),
(4,2200, 'Name', '2022-01-04 02:23', 'Bilbo Baggins'),
(5,9999, 'phone', '2022-02-05 12:23', 'Golum'),
(6,9999, 'address', '2022-03-06 20:00', 'Sauron'),
(7,1223, 'address', '2022-04-07 01:24', 'Gandalf'),
(8,2200, 'email', '2022-05-08 12:50', 'Some Urkai'),
(9,3412, 'email, phone', '2022-06-08 08:45', 'Golum'),
(10,1223, 'address', '2022-07-10 00:23', 'Pippin'),
(11,3412, 'email, address', '2022-09-22 16:48', 'Gandalf')
)sub(Update_ID, Cust_Id , Field_updated , Last_updated_date, Updated_by)
ORDER BY
MAX(Last_updated_date) OVER (PARTITION BY cust_id) DESC
,Last_updated_date DESC
Returns:
Update_ID Cust_Id Field_updated Last_updated_date Updated_by
----------------------------------------------------------------------------------
11 3412 email, address 2022-09-22 16:48 Gandalf
9 3412 email, phone 2022-06-08 08:45 Golum
10 1223 address 2022-07-10 00:23 Pippin
7 1223 address 2022-04-07 01:24 Gandalf
1 1223 Name 2021-11-01 12:23 Frodo Baggins
8 2200 email 2022-05-08 12:50 Some Urkai
4 2200 Name 2022-01-04 02:23 Bilbo Baggins
3 2200 phone 2021-12-03 23:00 Bilbo Baggins
6 9999 address 2022-03-06 20:00 Sauron
5 9999 phone 2022-02-05 12:23 Golum
2 9999 address 2021-12-02 19:23 Legolas
You can do:
select t.*
from customer_updates t
join (
select cust_id, dense_rank() over(order by max(last_updated_date)) as rk
from customer_updates
group by cust_id
) x on x.cust_id = t.cust_id
order by x.rk desc, t.last_updated_date desc
Result:
update_id Cust_Id Field_updated Last_updated_date Updated_by
---------- -------- --------------- ------------------ -------------
11 3412 email, address 2022-09-22 16:48 Gandalf
9 3412 email, phone 2022-06-08 08:45 Golum
10 1223 address 2022-07-10 00:23 Pippin
7 1223 address 2022-04-07 01:24 Gandalf
1 1223 Name 2021-11-01 12:23 Frodo Baggins
8 2200 email 2022-05-08 12:50 Some Urkai
4 2200 Name 2022-01-04 02:23 Bilbo Baggins
3 2200 phone 2021-12-03 23:00 Bilbo Baggins
6 9999 address 2022-03-06 20:00 Sauron
5 9999 phone 2022-02-05 12:23 Golum
2 9999 address 2021-12-02 19:23 Legolas
See running example at db<>fiddle.

How to count the number of campaigns per day based on the start and end dates of the campaigns in SQL

I need to count the number of campaigns per day based on the start and end dates of the campaigns
Input Table:
Campaign name
Start date
End date
Campaign A
2022-07-10
2022-09-25
Campaign B
2022-08-06
2022-10-07
Campaign C
2022-07-30
2022-09-10
Campaign D
2022-08-26
2022-10-24
Campaign E
2022-07-17
2022-09-29
Campaign F
2022-08-24
2022-09-12
Campaign G
2022-08-11
2022-10-24
Campaign H
2022-08-26
2022-11-22
Campaign I
2022-08-29
2022-09-25
Campaign J
2022-08-21
2022-11-15
Campaign K
2022-07-20
2022-09-18
Campaign L
2022-07-31
2022-11-20
Campaign M
2022-08-17
2022-10-10
Campaign N
2022-07-27
2022-09-07
Campaign O
2022-07-29
2022-09-26
Campaign P
2022-07-06
2022-09-15
Campaign Q
2022-07-16
2022-09-22
Out needed (result):
Date
Count unique campaigns
2022-07-02
17
2022-07-03
47
2022-07-04
5
2022-07-05
5
2022-07-06
25
2022-07-07
27
2022-07-08
17
2022-07-09
58
2022-07-10
23
2022-07-11
53
2022-07-12
18
2022-07-13
29
2022-07-14
52
2022-07-15
7
2022-07-16
17
2022-07-17
37
2022-07-18
33
How do I need to write the SQL command to get the above result? thanks all
In the following solutions we leverage string_split with combination with replicate to generate new records.
select dt as date
,count(*) as Count_unique_campaigns
from
(
select *
,dateadd(day, row_number() over(partition by Campaign_name order by (select null))-1, Start_date) as dt
from (
select *
from t
outer apply string_split(replicate(',',datediff(day, Start_date, End_date)),',')
) t
) t
group by dt
order by dt
date
Count_unique_campaigns
2022-07-06
1
2022-07-07
1
2022-07-08
1
2022-07-09
1
2022-07-10
2
2022-07-11
2
2022-07-12
2
2022-07-13
2
2022-07-14
2
2022-07-15
2
2022-07-16
3
2022-07-17
4
2022-07-18
4
2022-07-19
4
2022-07-20
5
2022-07-21
5
2022-07-22
5
2022-07-23
5
2022-07-24
5
2022-07-25
5
2022-07-26
5
2022-07-27
6
2022-07-28
6
2022-07-29
7
2022-07-30
8
2022-07-31
9
2022-08-01
9
2022-08-02
9
2022-08-03
9
2022-08-04
9
2022-08-05
9
2022-08-06
10
2022-08-07
10
2022-08-08
10
2022-08-09
10
2022-08-10
10
2022-08-11
11
2022-08-12
11
2022-08-13
11
2022-08-14
11
2022-08-15
11
2022-08-16
11
2022-08-17
12
2022-08-18
12
2022-08-19
12
2022-08-20
12
2022-08-21
13
2022-08-22
13
2022-08-23
13
2022-08-24
14
2022-08-25
14
2022-08-26
16
2022-08-27
16
2022-08-28
16
2022-08-29
17
2022-08-30
17
2022-08-31
17
2022-09-01
17
2022-09-02
17
2022-09-03
17
2022-09-04
17
2022-09-05
17
2022-09-06
17
2022-09-07
17
2022-09-08
16
2022-09-09
16
2022-09-10
16
2022-09-11
15
2022-09-12
15
2022-09-13
14
2022-09-14
14
2022-09-15
14
2022-09-16
13
2022-09-17
13
2022-09-18
13
2022-09-19
12
2022-09-20
12
2022-09-21
12
2022-09-22
12
2022-09-23
11
2022-09-24
11
2022-09-25
11
2022-09-26
9
2022-09-27
8
2022-09-28
8
2022-09-29
8
2022-09-30
7
2022-10-01
7
2022-10-02
7
2022-10-03
7
2022-10-04
7
2022-10-05
7
2022-10-06
7
2022-10-07
7
2022-10-08
6
2022-10-09
6
2022-10-10
6
2022-10-11
5
2022-10-12
5
2022-10-13
5
2022-10-14
5
2022-10-15
5
2022-10-16
5
2022-10-17
5
2022-10-18
5
2022-10-19
5
2022-10-20
5
2022-10-21
5
2022-10-22
5
2022-10-23
5
2022-10-24
5
2022-10-25
3
2022-10-26
3
2022-10-27
3
2022-10-28
3
2022-10-29
3
2022-10-30
3
2022-10-31
3
2022-11-01
3
2022-11-02
3
2022-11-03
3
2022-11-04
3
2022-11-05
3
2022-11-06
3
2022-11-07
3
2022-11-08
3
2022-11-09
3
2022-11-10
3
2022-11-11
3
2022-11-12
3
2022-11-13
3
2022-11-14
3
2022-11-15
3
2022-11-16
2
2022-11-17
2
2022-11-18
2
2022-11-19
2
2022-11-20
2
2022-11-21
1
2022-11-22
1
For SQL in Azure and SQL Server 2022 we have a cleaner solution based on [ordinal][4].
"The enable_ordinal argument and ordinal output column are currently
supported in Azure SQL Database, Azure SQL Managed Instance, and Azure
Synapse Analytics (serverless SQL pool only). Beginning with SQL
Server 2022 (16.x) Preview, the argument and output column are
available in SQL Server."
select dt as date
,count(*) as Count_unique_campaigns
from
(
select *
,dateadd(day, ordinal-1, Start_date) as dt
from (
select *
from t
outer apply string_split(replicate(',',datediff(day, Start_date, End_date)),',', 1)
) t
) t
group by dt
order by dt
Fiddle
Your sample data doesn't seem to match your desired results, but I think what you're after is this:
DECLARE #Start date, #End date;
-- first, find the earliest and last date:
SELECT #Start = MIN([Start date]), #End = MAX([End date])
FROM dbo.Campaigns;
-- now use a recursive CTE to build a date range,
-- and count the number of campaigns that have a row
-- where the campaign was active on that date:
WITH d(d) AS
(
SELECT #Start
UNION ALL
SELECT DATEADD(DAY, 1, d) FROM d WHERE d < #End
)
SELECT
[Date] = d,
[Count unique campaigns] = COUNT(*)
FROM d
INNER JOIN dbo.Campaigns AS c
ON d.d >= c.[Start date] AND d.d <= c.[End date]
GROUP BY d.d OPTION (MAXRECURSION 32767);
Working example in this fiddle.

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

SQL: Rank / Group a Column by Date

Using SQL Server Management Studio v17.9.1
I'm trying to rank / order / group some data by Site and Area by Date, but I'm struggling to get my head around not ranking the area alphabetically and ranking it by the earliest date it appears.
Here's the data I have:
Site | Area | Space | Date
DCG X 7 02/02/2020 12:13
DCG X 5 04/02/2020 11:47
DCG X 12 10/02/2020 15:14
GNL U 0 03/03/2020 18:35
GNL A 4 04/03/2020 08:28
GNL C 4 06/03/2020 09:07
GNL B 1 16/03/2020 07:10
DPL U 0 18/03/2020 09:28
DPL A 1 18/03/2020 09:36
DPL A 1 20/03/2020 20:04
SGR F 2 21/03/2020 19:42
SGR B 2 22/03/2020 10:30
SGR C 3 24/03/2020 08:17
SGR F 1 01/04/2020 09:00
SGR E 1 02/02/2020 10:57
SGR F 1 02/02/2020 15:50
I want to add 2 columns that rank / group the site and the area in ascending order of date, like so:
Site | Area | Space | Date | Site Order | Area Order |
DCG X 7 02/02/2020 12:13 1 1
DCG X 5 04/02/2020 11:47 1 1
DCG X 12 10/02/2020 15:14 1 1
GNL U 0 03/03/2020 18:35 2 1
GNL A 4 04/03/2020 08:28 2 2
GNL C 4 06/03/2020 09:07 2 3
GNL B 1 16/03/2020 07:10 2 4
DPL U 0 18/03/2020 09:28 3 1
DPL A 1 18/03/2020 09:36 3 2
DPL A 1 20/03/2020 20:04 3 2
SGR F 2 21/03/2020 19:42 4 1
SGR B 2 22/03/2020 10:30 4 2
SGR C 3 24/03/2020 08:17 4 3
SGR F 1 01/04/2020 09:00 4 1
SGR E 1 02/02/2020 10:57 4 4
SGR F 1 02/02/2020 15:50 4 1
Apologies if I've not made it clear
You can use min() as a window function to get the minimum date for each site and site/area combo. Then use dense_rank():
select t.*,
dense_rank() over (order by min_site_date, site) as site_seqnum,
dense_rank() over (partition by site order by min_site_date) as area_seqnum
from (select t.*,
min(date) over (partition by site) as min_site_date,
min(date) over (partition by site, area) as min_site_area_date
from t
) t
You can use window function :
select t.*,
dense_rank() over (order by site, site_date) as site_sequence,
dense_rank() over (partition by site order by area, site_area_date) as area_sequence
from (select t.*,
min([date]) over (partition by [site]) as site_date,
min([date]) over (partition by [site], area) as site_area_date
from table t
) t;

DENSE_RANK() OVER (Order by UniqueIdentifer) issue

I'm struggling trying to get DENSE_RANK to do what I want it to do.
It is basically to create a unique invoice number based on a unique identifier, but it needs to go up in order based on the date/time of the invoice.
For example I need:
InvoiceNo TxnId TxnDate
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:01
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:02
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:03
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:04
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:05
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:06
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:07
1 6C952E91-B888-4244-9079-14FBECAE0BA2 02/01/2014 00:08
2 8A5BCC36-8A70-4BE1-9FAB-A33BDD5BB78F 02/02/2014 00:09
2 8A5BCC36-8A70-4BE1-9FAB-A33BDD5BB78F 02/02/2014 00:09
3 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:10
3 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:20
3 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:21
3 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:23
But what I get when using DENSE_RANK OVER (Order by TxnId) is:
InvoiceNo TxnId TxnDate
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:02
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:01
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:03
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:04
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:06
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:05
1 6C952E91-B888-4244-9079-14FBECAE0BA2 02/01/2014 00:08
1 6C952E91-B888-4244-9079-14FBECAE0BA2 01/01/2014 00:07
2 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:10
2 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:21
2 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:20
2 83168B53-1647-4EB9-AF17-0B285EAA69B4 03/03/2014 00:23
3 8A5BCC36-8A70-4BE1-9FAB-A33BDD5BB78F 02/02/2014 00:09
3 8A5BCC36-8A70-4BE1-9FAB-A33BDD5BB78F 02/02/2014 00:09
If I do DENSE_RANK OVER(TxnId,TxnDate), it is a complete mess and doesn't do what I want either.
Any ideas guys? Am I even using the write function to do this? Any help appreciated :)
I think you want:
select dense_rank() over (order by txnid, txndate)
Everything with the same transaction id and date will have the same value.
EDIT:
If you need to extract the date, then that depends on the database. It would look something like this. For Oracle:
select dense_rank() over (order by txnid, trunc(txndate))
For Postgres:
select dense_rank() over (order by txnid, date_trunc('day', txndate))
For SQL Server:
select dense_rank() over (order by txnid, cast(txndate as date))
EDIT II:
You want the transactions ordered by the earliest date. Get the earliest date and then do the dense_rank():
select dense_rank() over (order by txnmindate, txnid)
from (select t.*, min(txndate) over (partition by txnid) as txnmindate
from table t
) t