SQL Grouping in sequence & Sequential ID for group - sql

I have below SQL database and would like to group them in sequence and assign ID to each group.
Time
Line
Colour
2021-11-02 3:00:00PM
1
Black
2021-11-02 3:00:01PM
1
White
2021-11-02 3:00:02PM
1
Red
2021-11-02 3:00:04PM
1
Red
2021-11-02 3:00:05PM
1
Black
2021-11-02 3:00:06PM
1
Black
2021-11-02 3:00:00PM
2
Black
2021-11-02 3:00:01PM
2
Black
2021-11-02 3:00:02PM
2
White
2021-11-02 3:00:03PM
2
White
2021-11-02 3:00:03PM
2
White
2021-11-02 3:00:03PM
2
Black
2021-11-02 3:00:03PM
2
Black
Result that I am looking for is
Time
Line
Colour
Qty
Group ID
2021-11-02 3:00:00PM
1
Black
1
1
2021-11-02 3:00:01PM
1
White
1
2
2021-11-02 3:00:02PM
1
Red
2
3
2021-11-02 3:00:04PM
1
Red
2
3
2021-11-02 3:00:05PM
1
Black
2
4
2021-11-02 3:00:06PM
1
Black
2
4
2021-11-02 3:00:00PM
2
Black
2
1
2021-11-02 3:00:01PM
2
Black
2
1
2021-11-02 3:00:02PM
2
White
3
2
2021-11-02 3:00:02PM
2
White
3
2
2021-11-02 3:00:03PM
2
White
3
2
2021-11-02 3:00:04PM
2
Black
2
3
2021-11-02 3:00:05PM
2
Black
2
3
Qty is basically # of same colour from line in a row.
Group ID is sequential ID for colour change by line.
I just couldn't figure out as it needs to be sequential in 'Time' then 'Line' columns and unable to aggregate.

Here is how you can do it:
SELECT * , COUNT(*) OVER (PARTITION BY Line, groupId) Qty
FROM (
SELECT *
, rank() OVER (PARTITION BY Line ORDER BY Insertdate)
- rank() OVER (PARTITION BY Line, colour ORDER BY Insertdate) AS GroupId
FROM tablename
) t ORDER BY line, Insertdate
db<>fiddle here

Related

Grouped differences in timestampls in SQLite3

I have a table that looks like the following:
Transaction ID
Timestamp
User ID
1
2021-11-02 8:08
USER1
2
2021-11-02 8:10
USER2
3
2021-11-02 8:07
USER2
4
2021-11-02 8:15
USER1
5
2021-11-02 8:18
USER2
I want to create a third column, that essentially says, for a given transaction, how long since that users last transaction. Essentially, subtract the users last timestamp. The output table would look like this:
Transaction ID
Timestamp
User ID
Time Taken
1
2021-11-02 8:08
USER1
None
2
2021-11-02 8:10
USER2
3
3
2021-11-02 8:07
USER2
None
4
2021-11-02 8:15
USER1
7
5
2021-11-02 8:18
USER2
8
How can I do this with a query in SQlite3?
We can use LAG() along with the JULIANDAY() function here:
SELECT
TransactionID,
Timestamp,
UserID,
COALESCE(CAST((JULIANDAY(Timestamp) -
JULIANDAY(LAG(Timestamp) OVER (PARTITION BY UserID
ORDER BY Timestamp))) * 1440 AS INTEGER), 'None') AS "TimeTaken"
FROM yourTable
ORDER BY Timestamp;
Note that in order for the above to work, your text timestamps will have to be in a valid literal format. So instead of:
2021-11-02 8:08
you would need:
2021-11-02 08:08:00

finding the minimal date_time within a window of time using sql

Im trying to model some data using sql, the column i would like to generate is date_started - all others is given.
date_started = the minimal date_created with the same id1 and id2 in range of 2 hours
that not belong to any other group of rows.
for example, for date_created = 2021-11-02 05:23:41.769,
date_started = 2021-11-02 05:23:41.769 itself.
because 2021-11-02 04:10:39.823 is in range of two hours but belong to 2021-11-02 02:16:28.544 group already.
id1
id2
date_created
date_started
1
2
2021-11-02 02:16:28.544
2021-11-02 02:16:28.544
1
2
2021-11-02 02:52:52.504
2021-11-02 02:16:28.544
1
2
2021-11-02 04:10:39.823
2021-11-02 02:16:28.544
1
2
2021-11-02 05:23:41.769
2021-11-02 05:23:41.769
1
2
2021-11-02 06:33:11.564
2021-11-02 05:23:41.769
1
2
2021-11-02 08:30:14.564
2021-11-02 08:30:14.564
It is a little bit unclear what you mean as your description could be interpreted differently from what is done in your example (should a new session start whenever there is a 2h gap between the previous "first" activity or whenever there is 2h of no activity?). Either way I think looking into sessionization might be helpful here (includes lots of example code) as this is ultimately what you're trying to do.

Creating a timetable with SQL (calculated start times for slots) and filtering by a person to show them their slots

I'm working in iMIS CMS (iMIS 200) and trying to create an IQA (an iMIS query, using SQL) that will give me a timetable of slots assigned to people per day (I've got this working); but then I want to be able to filter that timetable on a person's profile so they just see the slots they are assigned to.
(This is for auditions for an orchestra. So people make an application per instrument, then those applications are assigned to audition slots, of which there are several slots per day)
As the start/end times for slots are calculated using SUM OVER, when I filter this query by the person ID, I lose the correct start/end times for slots (as the other slots aren't in the data for it to SUM, I guess!)
Table structure:
tblContacts
===========
ContactID ContactName
---------------------------
1 Steve Jones
2 Clare Philips
3 Bob Smith
4 Helen Winters
5 Graham North
6 Sarah Stuart
tblApplications
===============
AppID FKContactID Instrument
-----------------------------------
1 1 Violin
2 1 Viola
3 2 Cello
4 3 Cello
5 4 Trumpet
6 5 Clarinet
7 5 Horn
8 6 Trumpet
tblAuditionDays
===============
AudDayID AudDayDate AudDayVenue AudDayStart
-------------------------------------------------
1 16-Sep-19 London 10:00
2 17-Sep-19 Manchester 10:00
3 18-Sep-19 Birmingham 13:30
4 19-Sep-19 Leeds 10:00
5 19-Sep-19 Glasgow 11:30
tblAuditionSlots
================
SlotID FKAudDayID SlotOrder SlotType SlotDuration FKAppID
-----------------------------------------------------------------
1 1 1 Audition 20 3
2 1 2 Audition 20 4
3 1 3 Chat 10 3
4 1 5 Chat 10 4
5 1 4 Audition 20
6 2 1 Audition 20 1
7 2 2 Audition 20 6
8 2 4 Chat 10 6
9 2 3 Chat 10 1
10 2 5 Audition 20
11 3 2 Chat 10 8
12 3 1 Audition 20 2
13 3 4 Chat 5 2
14 3 3 Audition 20 8
15 5 1 Audition 30 5
16 5 2 Audition 30 7
17 5 3 Chat 15 7
18 5 4 Chat 15 5
Current SQL for listing all the slots each day (in date/slot order, with the slot timings calculcated correctly) is:
SELECT
[tblAuditionSlots].[SlotOrder] as [Order],
CASE
WHEN
SUM([tblAuditionSlots].[SlotDuration]) OVER (PARTITION BY [tblAuditionDays].[FKAudDayID] ORDER BY [tblAuditionSlots].[SlotOrder] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) is null
THEN
CONVERT(VARCHAR(5), [tblAuditionDays].[AudDayStart], 108)
ELSE
CONVERT(VARCHAR(5), Dateadd(minute, SUM([tblAuditionSlots].[SlotDuration]) OVER (PARTITION BY [tblAuditionDays].[FKAudDayID] ORDER BY [tblAuditionSlots].[SlotOrder] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), [tblAuditionDays].[AudDayStart]), 108)
END
+ ' - ' +
CASE
WHEN
SUM([tblAuditionSlots].[SlotDuration]) OVER (PARTITION BY [tblAuditionDays].[FKAudDayID] ORDER BY [tblAuditionSlots].[SlotOrder] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) is null
THEN
CONVERT(VARCHAR(5), [tblAuditionDays].[AudDayStart], 108)
ELSE
CONVERT(VARCHAR(5), Dateadd(minute, SUM([tblAuditionSlots].[SlotDuration]) OVER (PARTITION BY [tblAuditionDays].[FKAudDayID] ORDER BY [tblAuditionSlots].[SlotOrder] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), [tblAuditionDays].[AudDayStart]), 108)
END AS [Slot],
[tblAuditionSlots].[SlotType] AS [Type],
[tblContacts].[ContactName] as [Name],
FROM
tblAuditionSlots
LEFT JOIN tblAuditionDays ON tblAuditionSlots.FKAudDayID = tblAuditionDays.AudDayID
LEFT JOIN tblApplications ON tblAuditionSlots.FKAppID = tblApplications.AppID
LEFT JOIN tblContacts ON tblApplications.FKContactID = tblContacts.ContactID
GROUP BY
[tblAuditionSlots].[SlotOrder],
[tblAuditionSlots].[SlotType],
[tblAuditionSlots].[SlotDuration],
[tblAuditionDays].[AudDayStart],
[tblContacts].[ContactName],
[tblContacts].[ContactID],
[tblAuditionDays].[AudDayID],
[tblAuditionDays].[AudDayDate]
ORDER BY
[tblAuditionDays].[DayDate],
[tblAuditionSlots].[Order]
iMIS, the CMS we're using, is limited by what you can create in an IQA (query).
You can basically insert (some) SQL as a column and give it an alias; you can add (non-calculated) fields to the order by; you can't really control the Group By (whatever fields are added are included in the Group By).
Ultimately, I'd like to be able to filter this by a Contact ID so I can see all their audition slots, but with the times correctly calculated.
From the sample data, for example:
STEVE JONES AUDITIONS
=====================
Date Slot Venue Type Instrument
----------------------------------------------------------------
17-Sep-19 10:00 - 10:20 Manchester Audition Violin
17-Sep-19 10:40 - 10:50 Manchester Chat Violin
18-Sep-19 13:30 - 13:50 Birmingham Audition Viola
18-Sep-19 14:30 - 14:35 Birmingham Chat Viola
HELEN WINTERS AUDITIONS
=======================
Date Slot Venue Type Instrument
----------------------------------------------------------------
19-Sep-19 11:30 - 12:00 Glasgow Audition Trumpet
19-Sep-19 12:45 - 13:00 Glasgow Chat Trumpet
Hopefully that all makes sense and I've provided enough information.
(In this version of iMIS [200], you can't do subqueries, in case that comes up...)
Thanks so much in advance for whatever help/tips/advice you can offer!
Chris

Creating distinct serialno on unique "product numbers"

I have a table that looks like this:
StgID---|---ItemNumber
1 0034
2 0035
3 0036
4 0036
5 0036
6 0058
And I need a way to assign some sort of unique item number for each row where it would look like this:
StgID---|---ItemNumber--|--SerialID
1 0034 1
2 0035 2
3 0036 3
4 0036 3
5 0036 3
6 0058 4
You can use DENSE_RANK:
SELECT *,
DENSE_RANK() OVER(ORDER BY ItemNumber) SerialId
FROM dbo.YourTable;

Pivoting Timelogs in Sql Query

I am kind of stuck in querying my timelogs table,
the following are the sample data:
TimelogId EmployeeId RecordDate RecordTime Type
--------- ---------- ---------- ---------- ----
1 4 2016-07-01 07:18:37 1
2 4 2016-07-01 12:03:14 2
5 4 2016-07-01 12:08:02 1
6 4 2016-07-01 18:02:03 2
7 6 2016-07-19 07:24:15 1
8 5 2016-07-19 07:26:03 1
9 6 2016-07-19 12:15:26 2
10 5 2016-07-19 12:35:17 2
13 5 2016-07-19 12:36:14 1
16 6 2016-07-19 12:45:45 1
17 6 2016-07-19 17:10:22 2
18 5 2016-07-19 18:43:09 2
The required output:
Date EmployeeId Time_In Time_Out Time_In Time_Out
------- ---------- -------- -------- ------- -------
2016-07-01 4 07:18:37 12:03:14 12:08:03 18:02:03
2016-07-19 6 07:24:15 12:15:26 12:45:45 17:10:22
2016-07-19 5 07:26:03 12:35:17 12:36:14 18:43:08
Where Type (1) = time in and Type (2) = time out.
Employees are required to logout at 12nn then log back in again after a couple of minutes.
I tried using pivot based from the previous questions that i read here. Though this is the first time i tried to use pivot in tables.
select
*
FROM
(
select
EmployeeID,
RecordDate,
RecordTime,
Type
from tblTimeLogs
) d
PIVOT(
Max(RecordTime) <---- I think the problem is right around here
FOR Type in ([1],[2]) <----- plus i can't seem to rename this column names maybe i'll read a little further on this.
) piv;
Output of query:
EmployeeID RecordDate 1 2
---------- ---------- ------ ------
4 2016-07-01 12:08:02 18:02:03
5 2016-07-19 12:36:14 18:43:09
6 2016-07-19 12:45:45 17:10:22
is this possible? Thanks. :D
Edit:
as suggested by vercelli, another scenario like for example the user forgot that he/she already timed in just a couple of minutes ago so she timed in again.
e.g.
TimelogId EmployeeId RecordDate RecordTime Type
--------- ---------- ---------- ---------- ----
1 4 2016-07-01 07:18:37 1
2 4 2016-07-01 12:03:14 2
5 4 2016-07-01 12:08:02 1
6 4 2016-07-01 18:02:03 2
7 6 2016-07-19 07:24:15 1
8 5 2016-07-19 07:26:03 1
9 6 2016-07-19 12:15:26 2
10 5 2016-07-19 12:35:17 2
13 5 2016-07-19 12:36:14 1
16 6 2016-07-19 12:45:45 1
17 6 2016-07-19 17:10:22 2
18 5 2016-07-19 18:43:09 2
19 5 2016-07-20 08:13:35 1 <--- Time in
20 5 2016-07-20 08:14:35 1 <--- Timed In again
21 5 2016-07-20 12:15:12 2 <--- Time Out
I tried using the query of Mr. Vercelli:
select
EmployeeID as Emp, RecordDate, [1] as Time_In1, [2] as Time_Out1, [3] as Time_In2, [4] as Time_out2
FROM
(
select
EmployeeID,
RecordDate,
RecordTime,
ROW_NUMBER () over (partition by EmployeeId, RecordDate order by RecordTime, type) as rn
from tblTimeLogs
) d
PIVOT(
max(RecordTime)
FOR rn in ([1],[2],[3],[4])
) as piv;
Output of the new query:
Emp RecordDate Time_In1 Time_Out1 Time_In2 Time_Out2
---- ---------- --------- --------- -------- ---------
4 2016-07-01 07:18:37 12:03:14 12:08:02 18:02:03
5 2016-07-19 07:26:03 12:35:17 12:36:14 18:43:09
5 2016-07-20 08:13:35 08:14:35 12:15:12 Null <--- the problem is right around this portion
6 2016-07-19 07:24:15 12:15:26 12:45:45 17:10:22
Expected Output:
Emp RecordDate Time_In1 Time_Out1 Time_In2 Time_Out2
---- ---------- --------- --------- -------- ---------
4 2016-07-01 07:18:37 12:03:14 12:08:02 18:02:03
5 2016-07-19 07:26:03 12:35:17 12:36:14 18:43:09
5 2016-07-20 08:13:35 12:15:12 08:14:35 Null <--- the second time in would fall on the second 5th column (Time_In2) since the **Type** value is = 1
6 2016-07-19 07:24:15 12:15:26 12:45:45 17:10:22
Thanks for the help guys :D. I'm learning new things from this problem.
I think this is what you are looking for. Demo:
select
EmployeeID as Emp, RecordDate, [1] as Time_In1, [2] as Time_Out1, [3] as Time_In2, [4] as Time_out2
FROM
(
select
EmployeeID,
RecordDate,
RecordTime,
ROW_NUMBER () over (partition by EmployeeId, RecordDate order by RecordTime, type) as rn
from tblTimeLogs
) d
PIVOT(
max(RecordTime)
FOR rn in ([1],[2],[3],[4])
) as piv;
OUPUT
Emp RecordDate Time_In1 Time_Out1 Time_In2 Time_out2
4 2016-07-01 07:18:37 12:03:14 12:08:02 18:02:03
5 2016-07-19 07:26:03 12:35:17 12:36:14 18:43:09
6 2016-07-19 07:24:15 12:15:26 12:45:45 17:10:22
DEMO HERE
---Table Creattion Scripts
create table #test
(
employeeid int,
recorddate date,
recordtime time,
typee int
)
insert into #test values( 4 , '2016-07-01', '07:18:37', 1)
insert into #test values( 4 , '2016-07-01', '12:03:14', 2)
insert into #test values( 4 , '2016-07-01', '12:08:02', 1)
insert into #test values( 4 , '2016-07-01', '18:02:03', 2)
Query
;with cte
as
(
select
employeeid,
max(recorddate) as recorddate,
min(recordtime) as timein,
max(recordtime) as Timein1 ,
lead(min(recordtime)) over (partition by employeeid order by min(recordtime)) as 'timeout1',
lead(max(recordtime)) over (partition by employeeid order by max(recordtime)) as 'timeout2'
from #test
group by
employeeid,typee
)
select employeeid,recorddate,timein,timeout1,timein1,timeout2
from cte
where timeout1 is not null and timeout2 is not null