PostgreSQL: How to count requests by date if there is no request for a date in a table then 0? - sql

I have table, like this:
| id | datetime | resource |
|:---|---------:|:--------:|
| 1 |2019-12-18| /v1 |
| 2 |2019-12-18| /v1 |
| 3 |2019-12-18| /v2 |
| 4 |2019-12-27| /v3 |
I need count resource per day.
And I can't understand how to build query for getting like this:
| id | datetime | resource | count |
|:---|---------:|:--------:|:-----:|
| 1 |2019-12-18| /v1 | 2 |
| 2 |2019-12-18| /v2 | 1 |
| 3 |2019-12-18| /v3 | 0 |
| 4 |2019-12-27| /v3 | 1 |
| 5 |2019-12-27| /v1 | 0 |
| 6 |2019-12-27| /v2 | 0 |

One option would be using CROSS JOIN to determine cross product relation among resource and datetime columns and then LEFT JOIN to combine with subquery in which there are grouped resource and datetime columns containing aggregation :
SELECT row_number() over (ORDER BY datetime, count DESC, resource) AS ID,
q.*
FROM
( SELECT t3.datetime, t3.resource, COALESCE(t4.count,0) AS count
FROM
(
(SELECT distinct resource FROM tab) t1
CROSS JOIN (SELECT distinct datetime FROM tab) t2 ) t3
LEFT JOIN
(
SELECT datetime, resource,count(datetime) as count
FROM tab
GROUP BY datetime, resource
) t4
ON t4.datetime = t3.datetime
AND t4.resource = t3.resource
) q;
Demo

Please try like below. IE. Group by with datetime and resource then take the count for the same you will get the Output . Please try this.
SELECT datetime, resource,count(id) AS count
FROM public.test GROUP BY datetime,resource;
Output
datetime resource count
18-12-2019 /v2 1
18-12-2019 /v1 2
27-12-2019 /v3 1

Use a cross join to generate the rows. Then use a left join to bring in the original values and aggregation:
select row_number() over (order by r.resource, d.datetime) as seqnum,
d.datetime, r.resource,
count(t.id) as cnt
from (select distinct datetime from t) d cross join
(select distinct resource from t) r left join
t
on d.datetime = t.datetime and
r.resource = t.resource
group by d.datetime, r.resource
order by seqnum;
Here is a db<>fiddle.

Related

postgresql - How to get one row the min value

I have table (t_image) with this column
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
A | 2 | 20170213
A | 3 | 20170214
B | 4 | 20170201
B | 5 | 20170202
desired result is this
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
B | 4 | 20170201
In the above table, I want to retrieve 1 row for each datacd who has the minimum index date
Here is my query, but the result returns 2 rows for datacd A
select *
from (
select datacd, min(indexdate) as indexdate
from t_image
group by datacd
) as t1 inner join t_image as t2 on t2.datacd = t1.datacd and t2.indexdate = t1.indexdate;
The Postgres proprietary distinct on () operator is typically the fastest solution for greatest-n-per-group queries:
select distinct on (datacd) *
from t_image
order by datacd, indexdate;
One option uses ROW_NUMBER():
SELECT t.datacd,
t.imagecode,
t.indexdate
FROM
(
SELECT datacd, imagecode, indexdate,
ROW_NUMBER() OVER (PARTITION BY datacd ORDER BY indexdate) rn
FROM t_image
) t
WHERE t.rn = 1

SQL Server - Select Distinct of two columns, where the distinct column selected has a maximum value based on two other columns

I have 2 tables - TC and T, with columns specified below. TC maps to T on column T_ID.
TC
----
T_ID,
TC_ID
T
-----
T_ID,
V_ID,
Datetime,
Count
My current result set is:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2013-09-26 | 450600 |
2 | 1 | 2013-12-09 | 14700 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 7500 |
4 | 1 | 2014-01-22 | 1000 |
4 | 1 | 2013-12-05 | 0 |
4 | 2 | 2013-12-05 | 0 |
Using the following query:
select T.V_ID,
TC.TC_ID,
T.Datetime,
T.Count
from T
inner join TC
on TC.T_ID = T.T_ID
Result set I want:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2014-01-22 | 15000 |
4 | 1 | 2014-01-22 | 1000 |
4 | 2 | 2013-12-05 | 0 |
I want to write a query to select each distinct V_ID + TC_ID combination, but only with the maximum datetime, and for that datetime the maximum count. E.g. for the distinct combination of V_ID = 2 and TC_ID = 1, '2014-01-22' is the maximum datetime, and for that datetime, 15000 is the maximum count, so select this record for the new table. Any ideas? I don't know if this is too ambitious for a query and I should just handle the result set in code instead.
One method uses row_number():
select v_id, tc_id, datetime, count
from (select T.V_ID, TC.TC_ID, T.Datetime, T.Count,
row_number() over (partition by t.V_ID, tc.tc_id
order by datetime desc, count desc
) as seqnum
from t join
tc
on tc.t_id = t._id
) tt
where seqnum = 1;
The only issue is that some rows have the same maximum datetime value. SQL tables represent unordered sets, so there is no way to determine which is really the maximum -- unless the datetime really has a time component or another column specifies the ordering within a day.
It is possible to solve this using CTEs. First, extracting the data from your query. Second, get the maxdates. Third, get the highest count for each maxdate.:
;WITH Dataset AS
(
select T.V_ID,
TC.TC_ID,
T.[Datetime],
T.[Count]
from T
inner join TC
on TC.T_ID = T._ID
),
MaxDates AS
(
SELECT V_ID, TC_ID, MAX(t.[Datetime]) AS MaxDate
FROM Dataset t
GROUP BY t.V_ID, t.TC_ID
)
SELECT t.V_ID, t.TC_ID, t.[Datetime], MAX(t.[Count]) AS [Count]
FROM Dataset t
INNER JOIN MaxDates m ON t.V_ID = m.V_ID AND t.TC_ID = m.TC_ID AND m.MaxDate = t.[Datetime]
GROUP BY t.V_ID, t.TC_ID, t.[Datetime]
Just to keep it simple:
You need to group by T.V_ID,TC.TC_ID,
with selecting the max of date and then to get the maximum count, you must use a sub query as follows,
select T.V_ID,
TC.TC_ID,
max(T.Datetime) as Date_Time,
(select max(Count) from T as tb where v_ID = T.v_ID and DateTime = max(T.DateTime)) as Count
from T
inner join TC
on TC.T_ID = T._ID
group by T.V_ID,TC.TC_ID,

Selecting Top 1 for Every ID

I have the following table:
| ID | ExecOrd | date |
| 1 | 1.0 | 3/4/2014|
| 1 | 2.0 | 7/7/2014|
| 1 | 3.0 | 8/8/2014|
| 2 | 1.0 | 8/4/2013|
| 2 | 2.0 |12/2/2013|
| 2 | 3.0 | 1/3/2014|
| 2 | 4.0 | |
I need to get the date of the top ExecOrd per ID of about 8000 records, and so far I can only do it for one ID:
SELECT TOP 1 date
FROM TABLE
WHERE DATE IS NOT NULL and ID = '1'
ORDER BY ExecOrd DESC
A little help would be appreciated. I have been trying to find a similar question to mine with no success.
There are several ways of doing this. A generic approach is to join the table back to itself using max():
select t.date
from yourtable t
join (select max(execord) execord, id
from yourtable
group by id
) t2 on t.id = t2.id and t.execord = t2.execord
If you're using 2005+, I prefer to use row_number():
select date
from (
select row_number() over (partition by id order by execord desc) rn, date
from yourtable
) t
where rn = 1;
SQL Fiddle Demo
Note: they will give different results if ties exist.
;with cte as (
SELECT id,row_number() over(partition by ID order byExecOrd DESC) r
FROM TABLE WHERE DATE IS NOT NULL )
select id from
cte where r=1

how to query range?

Raw Data
| ID | STATUS |
| 1 | A |
| 2 | A |
| 3 | B |
| 4 | B |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
| 9 | C |
Result
| START | END |
| 1 | 2 |
| 6 | 8 |
Range of STATUS A
How to query ?
This should give you the correct ranges:
SELECT
STATUS,
MIN(ID),
max_id
FROM (
SELECT
t1.STATUS,
t1.ID,
COALESCE(MAX(t2.ID), t1.ID) max_id
FROM
yourtable t1 LEFT JOIN yourtable t2
ON t1.STATUS=t2.STATUS AND t1.ID<t2.ID
WHERE
NOT EXISTS (SELECT NULL
FROM yourtable t3
WHERE
t3.STATUS!=t1.STATUS
AND t3.ID>t1.ID AND t3.ID<t2.ID)
GROUP BY
t1.ID,
t1.STATUS
) s
WHERE
status = 'A'
GROUP BY
STATUS,
max_id
Please see fiddle here.
You are probably better off with a cursor-based solution or a client-side function.
However, if you were using Oracle - the following would work.
WITH LOWER_VALS AS
( -- All the Ids with no immediate predecessor
SELECT ROWNUM AS RN, STATUS, ID AS LOWER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD1
WHERE RD1.ID -1 NOT IN
(SELECT ID FROM RAWDATA PRED_TABLE WHERE PRED_TABLE.STATUS = RD1.STATUS)
ORDER BY STATUS, ID
)
) ,
UPPER_VALS AS
( -- All the Ids with no immediate successor
SELECT ROWNUM AS RN, STATUS, ID AS UPPER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD2
WHERE RD2.ID +1 NOT IN
(SELECT ID FROM RAWDATA SUCC_TABLE WHERE SUCC_TABLE.STATUS = RD2.STATUS)
ORDER BY STATUS, ID
)
)
SELECT
L.STATUS, L.LOWER, U.UPPER
FROM
LOWER_VALS L
JOIN UPPER_VALS U ON
U.RN = L.RN;
Results in the set
A 1 2
A 6 8
B 3 5
C 9 9
http://sqlfiddle.com/#!4/10184/2
There is not a lot to go on from what you put, but I think this might work. I am using T-SQL because I don't know what you are using?
SELECT
min(ID)
, max(ID)
FROM RawData
WHERE [Status] = 'A'

Select from results of query?

I have a query like this:
SELECT Weighings.Member, MIN(Sessions.DateTime) AS FirstDate, MAX(Sessions.DateTime) AS LastDate
FROM Weighings AS Weighings INNER JOIN
Sessions ON Sessions.SessionGUID = Weighings.Session
WHERE (Sessions.DateTime >= '01/01/2011')
GROUP BY Weighings.Member
ORDER BY Weighings.Member
It returns this:
Member | FirstDate | LastDate
Blah | 01/01/11 | 06/07/11
Blah2 | 02/03/11 | 05/07/11
I need to get the value of a cell Weight_kg in table Weighings for the returned values FirstDate and LastDate to give results like so:
Member | FirstWeight | LastWeight
Blah | 150Kg | 60KG
Blah2 | 70Kg | 72KG
I have tried all combinations of things but just can't work it out, any ideas?
EDIT
Tables:
Sessions
______________________
SessionGUID | DateTime
----------------------
12432524325 | 01/01/11
12432524324 | 01/08/11
12432524323 | 01/15/11
34257473563 | 03/05/11
43634574545 | 06/07/11
Weighings
_____________________________________
Member | Session | Weight_kg
-------------------------------------
vffd8fdg87f | 12432524325 | 150
vffd8fdg87f | 12432524324 | 120
vffd8fdg87f | 12432524323 | 110
ddffv89sdv8 | 34257473563 | 124
32878vfdsv8 | 43634574545 | 75
;with C as
(
select W.Member,
W.Weight_kg,
row_number() over(partition by W.Member order by S.datetime desc) as rnLast,
row_number() over(partition by W.Member order by S.datetime asc) as rnFirst
from Weighings as W
inner join Sessions as S
on S.sessionguid = W.Session and
S.DateTime >= '20110101'
)
select CF.Member,
CF.Weight_kg as FirstWeight,
CL.Weight_kg as LastWeigth
from C as CF
inner join C as CL
on CF.Member = CL.Member
where CF.rnFirst = 1 and
CL.rnLast = 1
Try here: https://data.stackexchange.com/stackoverflow/q/118518/
You can use the RANK..OVER stmt (works only on SQL 2k5+)
select fw.Member, st.Weight, en.Weight
from
(
select Member, Weight, RANK() OVER(PARTITION BY Member ORDER BY Weight) rnk
from Weighings
) st
inner join
(
select Member, Weight, RANK() OVER(PARTITION BY Member ORDER BY WeightDESC) rnk
from Weighings
) en on en.Member= st.Member and st.rnk = 1 and en.rnk = 1
You have two possibilities.
If you want to reuse the first SELECT more times, I'd suggest to sreate temporary table
CREATE TEMPORARY TABLE `tmpTable` AS SELECT /*the first select*/ ;
/*and then*/
SELECT * FROM `tmpTable` /*the second select from the first select*/
If you require the first select only once
SELECT first.*
FROM (SELECT /*the first select*/) AS first