I'm trying to fetch the first entry of each group after the custom ORDER BY but don't know how to select that first entry of each group. The groups should be ordered by the #team if exist, otherwise other team else NULL.
SELECT t1.*
FROM tbl t1
INNER JOIN tbl2 t2 ON t2.group_id = t1.group
WHERE t2.region = #region
ORDER BY
CASE
WHEN team=#team THEN 1
WHEN team is NOT NULL THEN 2
WHEN team is NULL THEN 3
END
Content of tbl
id group team
1 1 AA
2 1 BB
3 2 AA
4 2 CC
5 3 BB
6 3 NULL
7 4 NULL
Expected result when #team=AA
id group team
1 1 AA
3 2 AA
5 3 BB
7 4 NULL
Expected result when #team=BB
id group team
2 1 BB
3 2 AA
5 3 BB
7 4 NULL
Use your custom ordering logic with ROW_NUMBER:
WITH cte AS (
SELECT t1.*, ROW_NUMBER() OVER (PARTITION BY t1.`group`
ORDER BY CASE WHEN team = #team THEN 1
WHEN team IS NOT NULL THEN 2
ELSE 3 END) rn
FROM tbl t1
INNER JOIN tbl2 t2 ON t2.group_id = t1.`group`
WHERE t2.region = #region
)
SELECT id, `group`, team
FROM cte
WHERE rn = 1;
Side note: Avoid naming your table columns GROUP, as this is a reserved MySQL keyword, and therefore must always be escaped in backticks.
Related
i am trying to remove duplicate records having same hid values.
Here's the Fiddle:
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=86e8ed00cf0a496da490eae5d7aae093
Table product_match_unmatches:
ID hid flag
1 1 1
2 1 1
3 2 1
4 2 1
5 1 2
6 2 2
7 2 2
8 1 1
9 1 1
10 2 1
Now I want to remove duplicates hid from the table but for flag = 1 only.
This query will remove all duplicates except for the recent one, but irrespective of flag values:
DELETE pmu1
FROM dmf_product_match_unmatches as pmu1
LEFT JOIN ( SELECT MAX(ID) as ID, hid
FROM dmf_product_match_unmatches as pmu2
GROUP BY hid) pmu3 USING (ID, hid)
WHERE pmu3.ID IS NULL;
I tried to add where clause flag = 1 in the above query but this is not producing desired result.
DELETE pmu1
FROM dmf_product_match_unmatches as pmu1
LEFT JOIN ( SELECT MAX(ID) as ID, hid
FROM dmf_product_match_unmatches as pmu2
where flag = 1
GROUP BY hid
) pmu3 USING (ID, hid)
WHERE pmu3.ID IS NOT NULL;
The required output is:
ID hid flag
5 1 2
6 2 2
7 2 2
9 1 1
10 2 1
Do you need in
DELETE t1
FROM dmf_product_match_unmatches t1
JOIN dmf_product_match_unmatches t2 USING (hid, flag)
WHERE flag = 1
AND t1.id < t2.id;
?
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=a5e9e95335573ebedd45cdcd577b5602
Using row_number
DELETE pmu1
FROM dmf_product_match_unmatches pmu1
JOIN (select id,
row_number() over(partition by hid order by id desc) rn
from dmf_product_match_unmatches
where flag = 1
) as pmu3 ON pmu1.ID = pmu3.ID
WHERE pmu3.rn > 1;
In sql server you can use the EXCEPT set operator:
declare #flag int = 1
delete dmf_product_match_unmatches
where id in (
select id
from dmf_product_match_unmatches
where flag = #flag
except
select max(id) id
from dmf_product_match_unmatches
where flag = #flag
group by hid, flag
)
In mysql you can use NOT EXISTS
declare #flag int = 1
delete d1
from dmf_product_match_unmatches d1
where flag = #flag
and not exists (
select max(id) id
from dmf_product_match_unmatches d2
group by hid, flag
having d1.id = max(d2.id)
)
I want select rows from my table with last status_Id if there is a row with status_Id = 2 for that rows
ticketStatus_Id ticket_Id status_Id
======================================
1 1 1
2 1 2 -
3 1 3 *
4 2 1
5 3 1
6 3 2 - *
7 4 1
8 4 2 -
9 4 3
10 4 4 *
I want select just rows 3, 6, 10. there are another rows with status_Id = 2 (rows 2, 6, 8) for that ticket_Id,
In other word How to select rows 3,6,10 with ticket_Id =1,3,4 that there are another row with these ticket_Ids and status_Id=2 (rows 2,6,8)
If you want the complete row, then I would view this as exists:
select t.*
from t
where exists (select 1
from t t2
where t2.ticket_id = t.ticket_id and t2.status_id = 2
) and
t.status_Id = (select max(t2.status_id)
from t t2
where t2.ticket_id = t.ticket_id
);
If you just want the ticket_id and status_id (and not the whole row), I would recommend aggregation:
select ticket_id, max(status_id)
from t
group by ticket_id
having sum(status_id = 2) > 0;
In your case, ticketStatus_Id seems to increase with status_id, so you can use:
select max(ticketStatus_Id) as ticketStatus_Id, ticket_id, max(status_id) as Status_Id
from t
group by ticket_id
having sum(status_id = 2) > 0;
First, for each ticket we get the row with the highest status. We can do this with a self-join. Each row is joined with the row with the next highest status. We select the rows which have no higher status, those will be the highest. Here's a more detailed explanation.
select ts1.*
from ticket_statuses ts1
left outer join ticket_statuses ts2
on ts1.ticket_Id = ts2.ticket_Id
and ts1.status_Id < ts2.status_Id
where ts2.ticketStatus_Id is null
3 1 3
4 2 1
6 3 2
10 4 4
11 5 3
Note that I've added a curve-ball of 11, 5, 3 to ensure we only select tickets with a status of 2, not greater than 2.
Then we can use that as a CTE (or subquery if you're not using MySQL 8) and select only those tickets who have a status of 2.
with max_statuses as (
select ts1.*
from ticket_statuses ts1
left outer join ticket_statuses ts2
on ts1.ticket_Id = ts2.ticket_Id
and ts1.status_Id < ts2.status_Id
where ts2.ticketStatus_Id is null
)
select ms.*
from max_statuses ms
join ticket_statuses ts
on ms.ticket_id = ts.ticket_id
and ts.status_id = 2;
3 1 3
6 3 2
10 4 4
This approach ensures we select the complete rows with the highest statuses and any extra data they may contain.
dbfiddle
This is basicaly a "last row per group" problem. You will find some solutions here. My prefered solution would be:
select t.*
from (
select max(ticketStatus_Id) as ticketStatus_Id
from mytable
group by ticket_Id
) tmax
join mytable t using(ticketStatus_Id)
The difference in your question is that you have a condition requiring a specific value within the group. This can be solved with a JOIN within the subquery:
select t.*
from (
select max(t1.ticketStatus_Id) as ticketStatus_Id
from mytable t2
join mytable t1 using(ticket_Id)
where t2.status_Id = 2
group by t2.ticket_Id
) tmax
join mytable t using(ticketStatus_Id)
Result:
| ticketStatus_Id | ticket_Id | status_Id |
| --------------- | --------- | --------- |
| 3 | 1 | 3 |
| 6 | 3 | 2 |
| 10 | 4 | 4 |
View on DB Fiddle
A solution using window functions could be:
select ticketStatus_Id, ticket_Id, status_Id
from (
select *
, row_number() over (partition by ticket_Id order by ticketStatus_Id desc) as rn
, bit_or(status_Id = 2) over (partition by ticket_Id) > 0 as has_status2
from mytable
) x
where has_status2 and rn = 1
A quite expressive way is to use EXISTS and NOT EXISTS subquery conditions:
select t.*
from mytable t
where exists (
select *
from mytable t1
where t1.ticket_Id = t.ticket_Id
and t1.status_Id = 2
)
and not exists (
select *
from mytable t1
where t1.ticket_Id = t.ticket_Id
and t1.ticketStatus_Id > t.ticketStatus_Id
)
SELECT a.*
FROM t a
JOIN
(
SELECT ticket_id, MAX(status_id) max_status_id
FROM t
WHERE status_id >= 2
GROUP BY ticket_id
) b
ON a.ticket_id = b.ticket_id
AND a.status_id = b.max_status_id;
SELECT
MAX(m1.ticketstatus_Id) as ticket_status,
m1.ticket_Id as ticket,
MAX(m1.status_Id) as status
FROM mytable m1
WHERE
m1.ticket_Id in (select m2.ticket_Id from mytable m2 where m2.ticket_Id=m1.ticket_Id and m2.status_Id=2)
GROUP BY m1.ticket_Id
I need to process album count for each of the country per artist; however, I have a problem once I do group_concat for count in mysql, I search a bit in stackoverflow, I found I have to do sub select for group_concat. The problem is once I do the sub select in from I can not use a.id from the parent from filed table. I got error like following Unknown column 'a.id' in 'where clause'
This is the query:
SELECT a.seq_id, a.id
(SELECT GROUP_CONCAT(cnt) AS cnt FROM (
SELECT CONCAT_WS('-', mgr.country_code, count(mgr.media_id)) AS cnt
FROM music_album_artists AS ma
JOIN media_geo_restrict AS mgr ON ma.album_id = mgr.media_id
WHERE ma.artist_id = a.id
GROUP BY mgr.country_code
) count_table
) AS album_count
FROM music_artist AS a
WHERE a.seq_id > 0 and a.seq_id < 10000
The sample data in tables:
music_artists:
seq_id id name
1 1 Hola
2 2 Vivi
music_album_artists:
id artist_id album_id
1 1 1
2 1 2
3 1 5
4 1 10
5 2 2
6 2 10
6 2 1
media_geo_restrict:
album_id country_code
1 BE
1 CA
1 DE
1 US
2 CH
2 CA
2 CH
5 DE
10 US
The result I would like to have
seq_id id album_count
1 1 BE--1,CA--2,CH--1,DE--1,US--1
2 2 CA--1,US--2,CH--1
Here is what you need:
select seq_id, id, group_concat(concat(country_code, '--', qtd))
from (
select ma.seq_id, ma.id,
mgr.country_code, count(*) qtd
from music_artists ma
inner join music_album_artists maa
on ma.id = maa.artist_id
inner join media_geo_restrict mgr
on maa.album_id = mgr.album_id
where ma.seq_id > 0 and ma.seq_id < 10000
group by ma.seq_id, ma.id, ma.name,
mgr.country_code
) tb
group by seq_id, id
Here is the working sample: http://sqlfiddle.com/#!9/ff8b5/8
Try this and tell me:
SELECT a.seq_id, a.id, GROUP_CONCAT(cnt) AS cnt
FROM music_artist AS a,
(
SELECT ma.artist_id, CONCAT_WS('-', mgr.country_code, count(mgr.media_id)) AS cnt
FROM music_album_artists AS ma
JOIN media_geo_restrict AS mgr ON ma.album_id = mgr.album_id
GROUP BY mgr.country_code
) AS count_table
WHERE a.seq_id > 0 and a.seq_id < 10000
and a.id=count_table.artist_id
group by a.id
Complaint_status Table : multiple rows for a complaints
id complaint_id status_type status_value
1 11 2 0
2 11 2 2
3 11 2 1
4 11 2 2
Trying to get min(id) having status_type=2 and status_value=2 but showing null,have to use case statement for doing other stuff.
SELECT c3.id AS Ticket_id,
CASE
WHEN cs.status_value=2 THEN cs.created_at
ELSE NULL
END AS Closure_date
FROM complaint c3
INNER JOIN complaint_status cs ON cs.complaint_id=c3.id
WHERE cs.id IN
(SELECT min(id)
FROM complaint3_status
WHERE complaint_id=c3.id
AND status_type=2)
AND c3.id IN(11)
Here is one method that gives you the entire row:
select cs.*
from complaint_status cs
where status_type = 2 and status_value = 2
order by id asc
limit 1;
You can just use select id if that is all you want. I have no idea what case has to do with this query.
i have two tables as follows------
table-1
CalenderType periodNumber periodstartdate
1 1 01-01-2013
1 2 11-01-2013
1 3 15-01-2013
1 4 25-01-2013
2 1 01-01-2013
2 2 15-01-2013
2 3 20-01-2013
2 4 25-01-2013
table2
Incidents Date
xyz 02-01-2013
xxyyzz 03-01-2013
ccvvb 12-01-2013
vvfg 16-01-2013
x3 17-01-2013
x5 24-01-2013
Now i want to find out the number of incidents took place in a given period(the Calendar type may change on runtime like)
the query should look something like this
select .......
from ......
where CalendarType=1
which should return
CalendarType PeriodNumber Incidents
1 1 2
1 2 1
1 3 3
1 4 0
can someone suggest me an approach or any method how this can be achieved.
Note:each period is variable in size.peroid1 may have 10 days period2 may have 5 days etc.
I think this does what you want, although I don't understand how you arrived at your sample output:
select t.CalenderType, t.periodNumber, count(*) as Incidents
from Table1 t
inner join (
select t2.Date, t2.Incidents, max(t1.periodstartdate) as PeriodStartDate
from Table2 t2
inner join Table1 t1 on t2.Date >= t1.periodstartdate
where CalenderType = 1
group by t2.Date, t2.Incidents
) a on t.periodstartdate = a.PeriodStartDate
where CalenderType=1
group by t.CalenderType, t.periodNumber
SQL Fiddle Example
Try this, a bit more general solution,SQLFiddle (Thanks RedFilter for schema):
SELECT t1.CalenderType, t1.periodNumber, count(Incidents)
FROM Table1 t1, Table1 t11, Table2
WHERE
(
(
t1.CalenderType = t11.CalenderType
AND t1.periodNumber = t11.periodNumber - 1
AND Date BETWEEN t1.periodstartdate AND t11.periodstartdate
)
OR
(
t1.periodNumber = (SELECT MAX(periodNumber) FROM Table1 WHERE t1.CalenderType = CalenderType)
AND Date > t1.periodstartdate
)
)
GROUP BY t1.CalenderType, t1.periodNumber
ORDER BY t1.CalenderType, t1.periodNumber