Selecting one distinct row from group of entries - mysql

ID TYPE DATE
1 A 01/02/2019
1 B 01/21/2019
1 C 02/03/2019
2 A 01/04/2019
2 C 01/29/2019
3 A 01/14/2019
3 B 03/11/2019
So using the table above as an example what I'm trying to do with a similar table is extract a specific Type from each Distinct ID. So let's say I only want to Select Type B from each Distinct ID. Now, the big confusion starts for me when I incorporate the Date. I want to Select Type B from each ID but only if Type B is the most recent date.
So in this instance the only row with Type B as the last date would be the last row.
3 B 03/11/2019
Any suggestions as to what my query should look like?

With NOT EXISTS:
select t.* from tablename t
where t.type = 'B'
and not exists (
select 1 from tablename
where id = t.id and date > t.date
)
See the demo.
Results:
| ID | TYPE | DATE |
| --- | ---- | ------------------- |
| 3 | B | 2019-03-11 00:00:00 |

Related

Mysql Count row data by every date but only have few data date

I have a table "activity" like this
idEmployee | activity | Date
1 | a | 2019/01/01
1 | b | 2019/01/01
2 | c | 2019/01/01
2 | d | 2019/01/01
1 | e | 2019/01/02
2 | f | 2019/01/03
1 | f | 2019/01/03
3 | c | 2019/01/01
4 | d | 2019/01/03
1 | e | 2019/01/02
2 | f | 2019/01/03
and i want to count every date from 2019/01/01 - 2019/01/03 that has no activity by every idEmpolyee (as total_no_actitivity) like this
idEmployee | total_no_activity
1 | 0
2 | 1 (2019/01/02
3 | 2 (2019/01/02,2019/01/03)
4 | 2 (2019/01/01,2019/01/02)
but i only can select idemployee that has no activity , without count total_no_activity.
SELECT idEmployee, namaLengkap, date
FROM account LEFT JOIN timesheet USING (idEmployee)
WHERE NOT EXISTS (SELECT idEmployee
FROM timesheet
WHERE account.idEmployee = timesheet.idEmployee AND weekday(date) AND date between '2019/08/05' and '2019/08/09' AND idrole = '4' AND statusaktif = '1' )
ORDER BY idEmployee ASC
is it possible to count total_no_activity with table "activity" only?
SELECT idEmployee,
3 - COUNT(DISTINCT `Date`) total_no_activity
FROM account
WHERE `Date` BETWEEN `2019/01/01` AND `2019/01/03`
GROUP BY idEmployee
where 3 is the amount of days in the period if interest, inclusive.
If some idEmployee have no records at all in the period in interest then this value will not be listed in output.
unfortunately i need the idEmployee that have no records will be listed in the output
Assiming that you need all idEmployee values which are present in source table at least once (maybe even out of the period in interest) use
SELECT account.idEmployee,
3 - COUNT(DISTINCT account.`Date`) total_no_activity
FROM (SELECT DISTINCT idEmployee FROM account) all_employees
LEFT JOIN account USING (idEmployee)
WHERE account.`Date` BETWEEN `2019/01/01` AND `2019/01/03`
GROUP BY account.idEmployee
I would suggest:
select a.idEmployee,
(datediff(params.date2, params.date1) + 1 -
count(distinct ac.date)
) as missing_days
from (select date('2019-01-01') as date1, date('2019-01-03') as date2
) params cross join -- a convenience so we don't have to retype the constants
accounts a left join
activity ac
on ac.idEmployee = a.idEmployee and
ac.date >= params.date1 and
ac.date <= params.date2
group by a.idEmployee;
To prevent typos and to allow the dates to change easily, this introduces a subquery, params, that has the date values.

SQL select only items that happen after but not also before a certain date

I have a table in SQL that contains People's IDs, codes and entry dates for each code.
Table X:
PERSON_ID CODE ENTRY_DATE
1 A 2017-12-03
1 C 2016-01-13
1 C 2009-05-11
2 B 2007-03-25
2 F 2018-01-18
3 G 2003-04-09
And another table that contains the person_id and reference dates for each person.
Table Y:
PERSON_ID REF_DATE
1 2015-07-18
2 2017-06-17
3 2002-10-06
What I want to do is for each person select rows from table X for which codes happened after REF_DATE in TABLE Y but the CODE itself didn't also occur before REF_DATE. For Example, in the case of person 1, the codes that happened after 2015-07-18 are A (2017-12-03) and the first C (2016-01-13). But Since C also occurred before REF_DATE (2015-07-18) in 2009-05-11, C is not to be selected.
This is just an example, the actual tables have millions of rows and thousands of different codes so I can't manually type codes etc.
the expected result of the query in this example should be:
PERSON_ID CODE ENTRY_DATE
1 A 2017-12-03
2 F 2018-01-18
3 G 2003-04-09
Any idea how to code that in SQL ?
Thanks !
First you join both tables so you have REF_DATE then filter the rows to get only the ones after REF_DATE, but also make sure doesnt exist any row before that date with that code.
SQL DEMO
SELECT X.`PERSON_ID`, X.`CODE`, X.`ENTRY_DATE`, Y.`REF_DATE`
FROM TableX X
JOIN TableY Y
ON X.`PERSON_ID` = Y.`PERSON_ID`
WHERE X.`ENTRY_DATE` > Y.`REF_DATE`
AND NOT EXISTS (SELECT 1
FROM TableX
WHERE TableX.`PERSON_ID` = X.`PERSON_ID`
AND TableX.`CODE`= X.`CODE`
AND TableX.`ENTRY_DATE` < Y.`REF_DATE`
)
OUTPUT
| PERSON_ID | CODE | ENTRY_DATE | REF_DATE |
|-----------|------|----------------------|----------------------|
| 1 | A | 2017-12-03T00:00:00Z | 2015-07-18T00:00:00Z |
| 2 | F | 2018-01-18T00:00:00Z | 2017-06-17T00:00:00Z |
| 3 | G | 2003-04-09T00:00:00Z | 2002-10-06T00:00:00Z |

Group and order rows with multiple column MySQL

I want to rows according to same column value.
Suppose this is a table
id name topic
1 A t
2 B a
3 c t
4 d b
5 e b
6 f a
I want result something like this.
id name topic
1 A t
3 c t
2 B a
6 f a
4 d b
5 e b
As you can see these are not order by topic neither by id, it sort about that topic which come first if t come first sort t first, one second a come then sort according to a then b.
if you apply ORDER BY topic it sort a b t or in DESC t b a but required result is t a b
Any suggestion ?
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,topic CHAR(1) NOT NULL
);
INSERT INTO my_table VALUES
(1,'t'),
(2,'a'),
(3,'t'),
(4,'b'),
(5,'b'),
(6,'a');
SELECT x.*
FROM my_table x
JOIN
( SELECT topic, MIN(id) id FROM my_table GROUP BY topic ) y
ON y.topic = x.topic
ORDER
BY y.id,x.id;
+----+-------+
| id | topic |
+----+-------+
| 1 | t |
| 3 | t |
| 2 | a |
| 6 | a |
| 4 | b |
| 5 | b |
+----+-------+
You can use CASE expression in ORDER BY.
Query
select * from `your_table_name`
order by
case `topic`
when 't' then 1
when 'a' then 2
when 'b' then 3
else 4 end
, `name`;

MySQL Error to selecting data

I have two column one column associated with another...
Table:base_data
id |---name----|-----des
1 | some name1 | The description1
2 | some name2 | The description2
Table: photos
id |---p_id----|-----photo
1 | 1 | img1s.jpg
2 | 1 | img1w.jpg
3 | 2 | img2.jpg
4 | 2 | img14.jpg
5 | 2 | img15.jpg
I want to select all data from table 1(base_data) and one row from associated row from photos: table how can I do that ????
I don't want to select by greatest n per group I want to select all data from the first table and only one row of the second table which matches with the first table row id, just first match not other.
The Result I want...
id |---name----|---des----|---p_id----|---photo----|
1 | some name |the des..1| 1 | img1s.jpg|
2 | some name |the des..2| 2 | img2.jpg|
I suppose you want to associate base_data with the first photo taken, which should be the one with the lowest photos.id. In MySQL, you could write this as follows: Create an intermediate query which gives - for any p_id - the corresponding record with the lowest id. Then, left join base_data with this intermediate query result. Hope there are not to many typos in it :-) :
select b.id, p2.photo
from base_data b left join
(select p.photo, p.p_id, min(id) from photos p group by p.p_id) p2 on b.id = p2.p_id
If you want the alphanumerically lowest photo name, in MySQL you can do this:
select
t1.*,
t2.photo
from
base_data as t1
left join (
select
p_id,
min(photo) as photo
from
photos
group by
p_id
) as t2 on t2.p_id = t1.id;

Count number of rows that are at the minimum of a group MySQL

I have a table that contains all the distinct names from another table, and then a column that holds the minimum value that the name received. For example, the table looks like this:
table1
Name | min_value
a | 1
b | 2
c | 4
The original table looks like this:
table2
Name | value
a | 1
b | 2
c | 4
a | 2
c | 8
a | 1
I want to return the number of times that the minimum value occurs within the original table. So, in this example it would return something like this:
output_table
Name | times_at_min
a | 2
b | 1
c | 1
Any help would be appreciated, thanks in advance.
One way to do it is:
SELECT m.Name,
min_value,
COUNT(CASE WHEN m.value = min_value THEN 1 END) As times_at_min
FROM mytable AS m
INNER JOIN (
SELECT Name,
MIN(value) AS min_value
FROM mytable
GROUP BY Name ) AS g
ON m.Name = g.Name
GROUP BY Name
In a subquery you select MIN(value) per Name. Joining with the derived table of this subquery, you can perform conditional aggregation so as to calculate the number of times the minimum value appears in the original table.
Fiddle demo here