how can I have max dates to all values? - tsql

I'm trying to get from a "queue" table the date values for each element
from a table (only showing top 30)
element added processed
order-confirmation 2013-07-03 14:12:02 2013-07-03 14:12:03
virtual-product-splitter 2013-07-03 14:12:02 2013-07-03 14:12:07
fraud-protect 2013-07-03 14:12:02 2013-07-03 14:12:11
giftcard-creator 2013-07-03 14:12:02 2013-07-03 14:12:15
code-dispatcher 2013-07-03 14:12:02 0001-01-01 00:00:00
order-confirmation 2013-07-03 14:10:01 2013-07-03 14:10:02
virtual-product-splitter 2013-07-03 14:10:01 2013-07-03 14:10:06
fraud-protect 2013-07-03 14:10:01 2013-07-03 14:10:10
giftcard-creator 2013-07-03 14:10:01 2013-07-03 14:10:14
code-dispatcher 2013-07-03 14:10:01 2013-07-03 14:10:19
order-confirmation 2013-07-03 14:08:01 2013-07-03 14:08:02
virtual-product-splitter 2013-07-03 14:08:01 2013-07-03 14:08:05
fraud-protect 2013-07-03 14:08:01 2013-07-03 14:08:09
giftcard-creator 2013-07-03 14:08:01 2013-07-03 14:08:13
code-dispatcher 2013-07-03 14:08:01 2013-07-03 14:08:18
code-dispatcher 2013-07-03 14:06:02 2013-07-03 14:06:19
order-confirmation 2013-07-03 14:06:01 2013-07-03 14:06:02
virtual-product-splitter 2013-07-03 14:06:01 2013-07-03 14:06:06
fraud-protect 2013-07-03 14:06:01 2013-07-03 14:06:10
giftcard-creator 2013-07-03 14:06:01 2013-07-03 14:06:14
order-confirmation 2013-07-03 14:04:02 2013-07-03 14:04:03
virtual-product-splitter 2013-07-03 14:04:02 2013-07-03 14:04:07
fraud-protect 2013-07-03 14:04:02 2013-07-03 14:04:11
giftcard-creator 2013-07-03 14:04:02 2013-07-03 14:04:15
code-dispatcher 2013-07-03 14:04:02 2013-07-03 14:04:19
order-confirmation 2013-07-03 14:02:01 2013-07-03 14:02:03
virtual-product-splitter 2013-07-03 14:02:01 2013-07-03 14:02:06
fraud-protect 2013-07-03 14:02:01 2013-07-03 14:02:10
giftcard-creator 2013-07-03 14:02:01 2013-07-03 14:02:14
code-dispatcher 2013-07-03 14:02:01 2013-07-03 14:02:19
doing
select distinct element from sr_queue I get
'c5-code-integration'
'c5-debitor-integration'
'c5-order-integration'
'c5-product-integration'
'code-dispatcher'
'fraud-protect'
'giftcard-creator'
'order-confirmation'
'packaged-confirmation'
'virtual-product-splitter'
and I'm trying to attach the max date (as there's several) to each element, but doing
select element, max(added), processed
from sr_queue
where element in (
'c5-code-integration',
'c5-debitor-integration',
'c5-order-integration',
'c5-product-integration',
'code-dispatcher',
'fraud-protect',
'giftcard-creator',
'order-confirmation',
'packaged-confirmation',
'virtual-product-splitter')
how should I create the selection?
so I can get:
order-confirmation 2013-07-03 14:12:02 2013-07-03 14:12:03
virtual-product-splitter 2013-07-03 14:12:02 2013-07-03 14:12:07
fraud-protect           2013-07-03 14:12:02 2013-07-03 14:12:11
giftcard-creator            2013-07-03 14:12:02 2013-07-03 14:12:15
code-dispatcher         2013-07-03 14:12:02 0001-01-01 00:00:00
c5-code-integration 2013-07-03 14:12:02 2013-07-03 14:12:15
...
I'm completely blanked after 3 days working on code :(

select element, max(added), max(processed)
from sr_queue
group by element
EDIT:
select element, added, processed
from sr_queue q
where added = (SELECT MAX(added) FROM sr_queue s WHERE s.element = q.element)
Or another possibility:
SELECT element, added, processed
FROM sr_queue s
INNER JOIN (
SELECT element, MAX(added)
FROM sr_queue
GROUP BY element
) q ON s.element = q.element

Use GROUP BY instead of DISTINCT:
SELECT
element,
MAX(added)
FROM
sr_queue
GROUP BY
element

Assuming a recent version of MS SQL Server
select element, added, processed from
(select *, row_number() over (partition by element order by added desc) as ranker
from sr_queue q ) Z
where ranker = 1

Related

Postgresql order by created date and group by transaction id

My table format is like this
id
transaction_id
status
created_at
updated_at
uuid-1
a293b1fe0369e0198df3293a8aef9c97ea532b30
completed
2022-08-25 02:32:44
2022-08-25 02:32:44
uuid-2
a293b1fe0369e0198df3293a8aef9c97ea532b24
failed
2022-08-24 12:33:22
2022-08-24 12:33:22
uuid-3
3b97c805fc7ce00119433c5284102b47781f9f66
pending
2022-08-24 12:30:22
2022-08-24 12:33:22
uuid-4
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-23 9:32:14
2022-08-23 9:32:14
uuid-5
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-05 9:22:34
2022-08-05 9:22:34
uuid-6
a293b1fe0369e0198df3293a8aef9c97ea532b24
pending
2022-08-04 03:33:12
2022-08-04 03:33:12
uuid-7
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-01 4:04:25
2022-08-01 4:04:25
uuid-8
a293b1fe0369e0198df3293a8aef9c97ea532b30
pending
2022-07-20 7:43:22
2022-07-20 7:43:22
I am trying to get results in this order
Latest user submitted transaction on top
Then order the actions that happened on each transaction in their created order
actions order will be pending, failed, completed.
transaction_id
status
created_at
updated_at
3b97c805fc7ce00119433c5284102b47781f9f66
pending
2022-08-24 12:30:22
2022-08-24 12:33:22
a293b1fe0369e0198df3293a8aef9c97ea532b24
pending
2022-08-04 03:33:12
2022-08-04 03:33:12
a293b1fe0369e0198df3293a8aef9c97ea532b24
failed
2022-08-24 12:33:22
2022-08-24 12:33:22
a293b1fe0369e0198df3293a8aef9c97ea532b30
pending
2022-07-20 7:43:22
2022-07-20 7:43:22
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-01 4:04:25
2022-08-01 4:04:25
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-05 9:22:34
2022-08-05 9:22:34
a293b1fe0369e0198df3293a8aef9c97ea532b30
failed
2022-08-23 9:32:14
2022-08-23 9:32:14
a293b1fe0369e0198df3293a8aef9c97ea532b30
completed
2022-08-25 02:32:44
2022-08-25 02:32:44
I tried to group and order with RANK function like below, but no idea how to sort group by their first created date
select
transaction_id,
created_at,
status,
RANK() over (partition by transaction_id order by created_at) group_rank
from
transactions;
I would use ROW_NUMBER() and MAX() here:
WITH cte AS (
SELECT *, MAX(created_at) OVER (PARTITION BY transaction_id) AS max_created_at,
ROW_NUMBER() OVER (PARTITION BY transaction_id
ORDER BY CASE status WHEN 'pending' THEN 1
WHEN 'failed' THEN 2
WHEN 'completed' THEN 3 END,
created_at) rn
FROM transactions
)
SELECT transaction_id, status, created_at, updated_at
FROM cte
ORDER BY max_created_at DESC, rn;
The ordering logic is that we first order each block of records belonging to the same transaction using the most recent created timestamp. Next, within each block we order by status. Finally, for two or more records having the same status, we again break that tie using the created timestamp.

Postgres generate_series wrong result

I don't know if it's a bug or it's intended, but the simple query
select generate_series('2021-03-28'::date, '2021-03-29'::date - interval '1 minute', interval '1 hour') as date_hour;
> 2021-03-28 00:00:00.000
2021-03-28 01:00:00.000
2021-03-28 03:00:00.000 <---
2021-03-28 03:00:00.000 <---
2021-03-28 04:00:00.000
2021-03-28 05:00:00.000
2021-03-28 06:00:00.000
2021-03-28 07:00:00.000
2021-03-28 08:00:00.000
2021-03-28 09:00:00.000
2021-03-28 10:00:00.000
2021-03-28 11:00:00.000
2021-03-28 12:00:00.000
2021-03-28 13:00:00.000
2021-03-28 14:00:00.000
2021-03-28 15:00:00.000
2021-03-28 16:00:00.000
2021-03-28 17:00:00.000
2021-03-28 18:00:00.000
2021-03-28 19:00:00.000
2021-03-28 20:00:00.000
2021-03-28 21:00:00.000
2021-03-28 22:00:00.000
2021-03-28 23:00:00.000
generates a duplicate row 2021-03-28 03:00:00.000, as you can also see in the picture below.
What I'm missing here?
select version();
> PostgreSQL 14.4 (Ubuntu 14.4-1.pgdg20.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
UPDATE
Despite the result, under the scene it looks like the values are correctly different. I wonder if it's just a representation issue.
select date_trunc('hour', date_hour), extract(epoch from date_hour), count(*)
from (
select generate_series('2021-03-28'::date, '2021-03-29'::date - interval '1 minute', interval '1 hour') as date_hour
) s
group by date_trunc('hour', date_hour), extract(epoch from date_hour)
order by date_trunc('hour', date_hour), extract(epoch from date_hour)

How to get first available value in a column (not MIN) using aggregate function on a NVARCHAR type column?

I have a temp table (#TempTable) which looks like this:
AID StartTime EndTime StartSID EndSID Name
79F05D45 2013-07-02 2013-07-03 1226349 1227338
79F05D45 2013-07-03 2013-07-03 1227381 1227901
79F05D45 2013-07-03 2013-07-03 1233976 1233977 John Pringle
79F05D45 2013-07-03 2013-07-03 1234386 1234452
79F05D45 2013-07-03 2013-07-03 1235138 1235147
79F05D45 2013-07-03 2013-07-03 1235669 1235708 Mike Gordon
79F05D45 2013-07-03 2013-07-03 1235828 1239004 Jeff Smith
How do I use the Aggregate function on Name so that when I GROUP BY StartTime and EndTime I get John Pringle in the Name column (I tried using MIN(Name) but it gives me blank value and If I use MAX(Name) I get Jeff Smith )
Basically, my requirement is to get the first available value in column Name
Here is my Query:
SELECT
TT.AID,
MIN(StartTime) as StartTime,
MAX(EndTime) as Endtime,
MIN(StartSSID) as StartSID,
MAX(EndSSID) AS EndSID,
-- I tried MIN(Name) here but I get empty cell, MAX(Name) gives wrong result. Basically I want first available value in the Name column here (which is John Pringle).
FROM
#TempTable TT
GROUP BY TT.AID, StartTime, EndTime
Result I get:
AID StartTime EndTime StartSID EndSID Name
79F05D45 2013-07-02 2013-07-03 1226349 1227338
79F05D45 2013-07-03 2013-07-03 1227381 1239004
Result I am aiming for:
AID StartTime EndTime StartSID EndSID Name
79F05D45 2013-07-02 2013-07-03 1226349 1227338
79F05D45 2013-07-03 2013-07-03 1227381 1239004 John Pringle
Thanks!
;WITH a as
(
SELECT
AID,
StartTime,
EndTime,
StartSSID,
EndSSID,
rn = row_number() over (partition by AID,cast(starttime as date) order by case WHEN name = '' or name is null then '20990101' else starttime end, starttime)
FROM
#TempTable TT
)
SELECT AID, StartTime, EndTime, StartSSID, EndSSID
WHERE rn = 1

Select a row when data is missing

i got a question.
I use this straight foreward query to retrieve data on a daily basis. part of the data is an ID.
For example, i got ID's 001 002 003 and 004. Every ID has some columns with data.
I daily generate a report based on that data.
A typical day looks lke
ID Date Value
001 2013-07-02 900
002 2013-07-02 800
003 2013-07-02 750
004 2013-07-02 950
Select *
FROM
myTable
WHERE datum > now() - INTERVAL '2 days' and ht not in (select ht from blocked_ht)
order by ht, id;
Some times the import for 1 id fails. So my data looks like
ID Date Value
001 2013-07-02 900
003 2013-07-02 750
004 2013-07-02 950
Its vital to know that 1 ID is missing, visualized in my report (made in Japserreports)
So i instert an ID without a date and value 0 and eddited the query:
SELECT *
FROM
"lptv_import" lptv_import
WHERE datum > now() - INTERVAL '2 days' and ht not in (select ht from negeren_ht) OR datum IS NULL
order by ht, id;
Now the data looks like this:
001 2013-07-02 900
002 800
003 2013-07-02 750
004 2013-07-02 950
How can i select from the tabel the row without the date WHEN ID 002 WITH a date is missing?
Hmm, this looks more compliacted than i thought...
select
id, coalesce(datum::text, 'NULL') as "date", "value"
from
(
select distinct id
from lptv
) id
left join
lptv using (id)
where
datum > now() - INTERVAL '2 days'
and not exists (select ht from negeren_ht where ht = lptv.ht)
order by id

TSQL: How to apply Condition to sub grouping

Image I have the following table with multiple codes for a single person for different periods (id is the primary key)
id code Name Start Finish
325 1353 Bob NULL 2012-07-03 16:21:16.067
1742 1353 Bob 2012-07-03 16:21:16.067 2012-08-03 15:56:29.897
1803 1353 Bob 2012-08-03 15:56:29.897 NULL
17 575 Bob NULL NULL
270 834 Bob NULL 2012-07-20 15:51:19.913
1780 834 Bob 2012-07-20 15:51:19.913 2012-07-26 16:26:54.413
1789 834 Bob 2012-07-26 16:26:54.413 2012-08-21 15:36:58.940
1830 834 Bob 2012-08-21 15:36:58.940 2012-08-24 14:26:05.890
1835 834 Bob 2012-08-24 14:26:05.890 2012-08-30 12:01:05.313
1838 123 Bob 2012-08-30 12:01:05.313 2012-09-05 09:29:02.497
1844 900 Bob 2012-09-05 09:29:02.497 NULL
What I want to do update the table such that the code is take from the latest person.
id code Name Start Finish
325 900 Bob NULL 2012-07-03 16:21:16.067
1742 900 Bob 2012-07-03 16:21:16.067 2012-08-03 15:56:29.897
1803 900 Bob 2012-08-03 15:56:29.897 NULL
17 900 Bob NULL NULL
270 900 Bob NULL 2012-07-20 15:51:19.913
1780 900 Bob 2012-07-20 15:51:19.913 2012-07-26 16:26:54.413
1789 900 Bob 2012-07-26 16:26:54.413 2012-08-21 15:36:58.940
1830 900 Bob 2012-08-21 15:36:58.940 2012-08-24 14:26:05.890
1835 900 Bob 2012-08-24 14:26:05.890 2012-08-30 12:01:05.313
1838 900 Bob 2012-08-30 12:01:05.313 2012-09-05 09:29:02.497
1844 900 Bob 2012-09-05 09:29:02.497 NULL
Latest person is defined as the person with the latest (max?) Start AND (Finish IS NULL or Finish >= GetDate()) WITHIN the Group of people of same Name AND Code
In the above example that is where id = 1844 (with the groups of Bob it's got the latest Start and the Finish is Null)
I pretty sure this is possible with a single statement but I can see how to define 'Latest Person' such that I can join it back to get rows I want to update
Edit: Please note that I cannot rely on the ordering of the Id column only the date columns.
Something like this will do:
update this set code = (
select top (1) that.code from table1 that
where that.name = this.name -- match on name
and (that.Finish is null or that.Finish >= getdate()) -- filter for current rows only
order by that.Start desc, that.id desc -- rank by start, break ties with id
)
from table1 this
I hope your table is well indexed, and/or not too big, because this is expensive to do in one step.
Alternate form, using OUTER APPLY, and more easily extensible:
update this set code = that.code
from table1 this
outer apply (
select top (1) that.code from table1 that
where that.name = this.name -- match on name
and (that.Finish is null or that.Finish >= getdate()) -- filter for current rows
order by that.Start desc, that.id desc -- rank by start, break ties with id
) that
Alternate method using windowing functions, without a join:
update this set code = _latest_code
from (
-- identify the latest code per name
select *, _latest_code = max(
case
when (finish is null or finish >= getdate())
and _row_number = 1
then code else null
end
) over (partition by name)
from (
-- identify the latest row per name
select *, _row_number = row_number() over (
partition by name order by
case when finish is null or finish >= getdate() then 0 else 1 end
, start desc, id desc)
from table1
) this
) this