Alright, I have those columns on MySQL :
id
id_conv
associated_statut
The associated_statut is a number between 1 and 7.
What I want to do is to count only the id_conv if the LAST associated_statut for this id_conv is 2 for example.
Example :
-----------------------------------------------
| id | id_conv | associated_statut |
-----------------------------------------------
| 1 | 15 | 1 |
| 2 | 15 | 2 |
| 3 | 15 | 2 |
| 4 | 15 | 4 |
| 5 | 15 | 2 |
| 6 | 15 | 3 |
The id_conv would NOT be counted if I want the associated_statut = 2, because the last associated_statut for this id_conv is 3.
I already tried this query :
SELECT COUNT(DISTINCT id_conv) FROM MyTable WHERE associated_statut = 2
But this doesn't returns what I want.
Is there a way to do this in SQL ?
Thanks.
Maybe, this will work for you:
SELECT count(t1.id) FROM mytable t1
INNER JOIN (SELECT id_conv, MAX(id) id FROM foo GROUP BY id_conv) t2
ON t1.id = t2.id
WHERE t1.associated_statut = 2
SELECT COUNT(sub1.id_conv) FROM MyTable
INNER JOIN
(
SELECT DISTINCT id, FIRST(associated_statut ORDER BY id DESC)
group by id_conv
recent FROM MyTable
) sub1 ON sub1.id = MyTable.id
WHERE sub1.recent_associated_statut = 2
We can do same thing without sub query. It will take less time when you have more data.
SELECT count(t1.id) FROM
mytable t1
LEFT JOIN
mytable t2
ON t1.id_conv = t2.id_conv
AND t1.id < t2.id
WHERE t2.id IS NULL
AND t1.associated_statut = 2;
Related
Hi! this work fine, but i need count more sons but whit a condition
select t1.*,(select count(*)
from tabl t2
where t2.tabl = t1.id) as sons
from tabl t1 where tabl.sons = ?;
I try this, but receive the following error...
SQL ERROR: Operand should contain 1 column(s)
select t1.*,(select count(*),(select count(*) from tbl1 t3 where t3.type = 3) as Johnny
from tabl t2
where t2.tabl = t1.id) as sons
from tabl t1 where tabl.sons = ?;
please, and thanks
Edit:
this do exactly i want, but i think is not the correct way to do
(i changed the names sorry, but it look better)
select m1.*,
(select count(*) from node m2 where m2.nodeid = m1.id) as child,
(select count(*) from node m3 where m3.type = 3 and m3.nodeid = m1.id) as del,
(select count(*) from node m3 where m3.type = 1 and m3.nodeid = m1.id) as edit,
(select count(*) from node m3 where m3.type = 4 and m3.nodeid = m1.id) as protect,
(select count(*) from node m3 where m3.type = 2 and m3.nodeid = m1.id) as move
from node m1 where nodeid = ?
+----+--------+------+-------+------+------+---------+------+
| id | nodeid | type | child | del | edit | protect | move |
+----+--------+------+-------+------+------+---------+------+
| 1 | null | 0 | 3 | 0 | 1 | 1 | 1 |
+----+--------+------+-------+------+------+---------+------+
+----+--------+------+-------+------+------+---------+------+
| id | nodeid | type | child | del | edit | protect | move |
+----+--------+------+-------+------+------+---------+------+
| 34 | 1 | 1 | 7 | 2 | 1 | 1 | 1 |
| 23 | 1 | 2 | 3 | 1 | 0 | 0 | 0 |
| 32 | 1 | 3 | 2 | 0 | 0 | 0 | 0 |
+----+--------+------+-------+------+------+---------+------+
basically how many children are and how many are of each type xd
MySQL 8 has got the window functions. Therefore, you can write your query in it like this:
SELECT t1.*, COUNT(*) OVER(PARTITION BY t1.id ORDER BY t1.id) AS sons,
COUNT(CASE WHEN t1.type = 3 THEN t1.type END) OVER (PARTITION BY t1.id ORDER BY t1.id) AS Johnny
FROM tabl t1
WHERE t1.sons = ?;
You cannot define multiple columns to one column.
(select count(*),(select count(*) from tbl1 t3 where t3.type = 3) as Johnny
from tabl t2 where t2.tabl = t1.id) as sons
sons : one column, count(*),,,Johnny : multiple column
Please change it to the following sql...
(select count(*) from tabl t2 where t2.tabl=t1.id), (select count(*) from tbl1 t3 where t3.type=3)
Is this what you are looking for?
select t.*,
count(*) over (partition by id) as sons,
sum(type = 3) over (partition by id) as johnny
from tabl t
having sons = ?;
MySQL extends the having clause so it can filter on table aliases in a non-aggregation query.
I'm trying to extract all rows from same Group until I hit breakpoint value B. The example data below is ordered virtual table:
+----+--------+------------+
| ID | Group | Breakpoint |
+----+--------+------------+
| 1 | 1 | A |
| 2 | 1 | A |
| 3 | 1 | B |
| 4 | 1 | A |
| 5 | 2 | A |
| 6 | 2 | A |
| 7 | 2 | A |
| 8 | 3 | A |
| 9 | 3 | B |
+----+--------+------------+
This would be my result.
+----+--------+------------+
| ID | Group | Breakpoint |
+----+--------+------------+
| 1 | 1 | A |
| 2 | 1 | A |
| 5 | 2 | A |
| 6 | 2 | A |
| 7 | 2 | A |
| 8 | 3 | A |
+----+--------+------------+
Notice that when there are both A and B breakpoint values within a group, I want to have the rows until the first A value in this order. If there are only A values for a group like in group 2, I want to have all of the items in the group.
Here's a simple solution that uses no subqueries or GROUP BY logic.
SELECT t1.ID, t1.Group, t1.Breakpoint
FROM MyTable AS t1
LEFT OUTER JOIN MyTable AS t2
ON t1.ID >= t2.ID AND t1.`Group` = t2.`Group` AND t2.Breakpoint = 'B'
WHERE t2.ID IS NULL
For each row t1, try to find another row t2 with 'B', in the same Group, with an earlier ID. If none is found, the OUTER JOIN guarantees that t2.ID is NULL. That will be true only up until the desired breakpoint.
From you example above, you are not really grouping the results. you just need to display the records where Breakpoint is A:
Select * From Table
Where Breakpint ='A'
You may use NOT EXISTS
select *
from your_table t1
where not exists (
select 1
from your_table t2
where t1.group = t2.group and t2.id <= t1.id and t2.breakpoint = 'B'
)
or ALL can work as well if you never have NULL in id
select *
from your_table t1
where t1.id < ALL(
select t2.id
from your_table t2
where t1.group = t2.group and t2.breakpoint = 'B'
)
Assuming that we are ordering by ID column, we could do something like this:
SELECT d.*
FROM mytable d
LEFT
JOIN ( SELECT bp.group
, MIN(bp.id) AS bp_id
FROM mytable bp
WHERE bp.breakpoint = 'B'
GROUP BY bp.group
) b
ON b.group = d.group
WHERE b.bp_id > d.id OR b.bp_id IS NULL
ORDER BY d.group, d.id
This takes into account cases where there is no breakpoint='B' row for a given group, and returns all of the rows for that group.
Note that the inline view b gets us the lowest id value from rows with breakpoint='B' for each group. We can outer join that to original table (matching on group), and then conditional tests in the WHERE clause to exclude rows that follow the first breakpoint='B' for each group.
SQL tables represent unordered sets. Hence, there is no "before" or "after" a particular row.
Let me assume that you have some column that specifies the ordering. I'll call it id. You can then do what you want with:
select t.*
from t
where t.id < (select min(t2.id) from t t2 where t2.group = t.group and t2.breakpoint = 'B');
To get all rows when if there are no 'B':
select t.*
from t
where t.id < (select coalesce(min(t2.id), t.id + 1) from t t2 where t2.group = t.group and t2.breakpoint = 'B');
I want to show my parent id with child record(duplicate record). Here is my table
ID|Name |Comments|
__|_____|________|_
1 |Test1|Unique |
2 |Test2|Unique |
3 |Test1|Unique |
4 |Test2|Unique |
5 |Test1|Unique |
6 |Test3|Unique |
Expected Result:
ID|Name |Comments |
__|_____|__________________|_
1 |Test1|Unique |
2 |Test2|Unique |
3 |Test1|Duplicate with: 1 |
4 |Test2|Duplicate with: 2 |
5 |Test1|Duplicate with: 1 |
6 |Test3|Unique |
not sure what the exact goal here, but here is a single query that get the job done:
mysql> select ID,tbl.Name,if(no!=ID,concat('Duplicate with: ',no),'Unique') Comments from tbl left join (select ID no,Name from tbl group by Name) T on T.Name=tbl.Name;
+----+-------+-------------------+
| ID | Name | Comments |
+----+-------+-------------------+
| 1 | Test1 | Unique |
| 2 | Test2 | Unique |
| 3 | Test1 | Duplicate with: 1 |
| 4 | Test2 | Duplicate with: 2 |
| 5 | Test1 | Duplicate with: 1 |
| 6 | Test3 | Unique |
+----+-------+-------------------+
Check This Live Demo using 'coalesce' and 'Case when'
Query :
select id
,name
,coalesce(
( select coalesce(case when min(id)>0 then concat('Duplicate with : ',min(id)) else null end,Comments)
from Yourtable t2 where t2.name = t.name and t2.id < t.id group by Comments)
,Comments) as Comments
from Yourtable t
order by id
Output :
hey you can try this query and it is giving expected result.
select t1.id,t1.`name`,
CASE WHEN (select count(`name`) from table_name t2 where t2.`name` = t1.`name` and t2.id <= t1.id ) = 1
then 'unique'
else CONCAT('Duplicate with :',(select min(t3.id) from table_name t3 where t3.name = t1.`name`))
end as 'comments'
from table_name t1
replace table_name with your table.
Hope this works for you. Ask if any doubt
Using only a single sub-query.
select id
,name
,coalesce
(
concat
(
'Duplicate with: '
,(select min(id) from mytable t2 where t2.name = t.name and t2.id < t.id)
)
,'Unique'
) as Comments
from mytable t
order by id
I have the following tables
tbl_investors
id | first_name | last_name |
---------------------------------------
1 | Jon | Cold |
2 | Rob | Ark |
3 | Rickon | Bolt |
tbl_investors_ledger
id | investor_id | amount |
------------------------------------
1 | 1 | 500 |
2 | 2 | 200 |
3 | 2 | 250 |
4 | 2 | 300 |
5 | 3 | 10 |
6 | 1 | 550 |
7 | 3 | 20 |
I just want to return all investors with their latest amount. Ex, Jon Cold with 550, Rob Ark 300 and Rickon Bolt 20, alphabetically with their last name.
I have an existing query but it will not return the latest amount of the investor. Can someone help me what i'm doing wrong?
SELECT t1.*, t2.*
FROM ".tbl_investors." t1
LEFT JOIN ".tbl_investors_ledger." t2
ON t1.id = t2.investor_id
LEFT JOIN (SELECT t.investor_id, max(t.id) as tid
FROM ".tbl_investors_ledger." t ) tt
ON tt.investor_id = t2.investor_id AND tt.tid = t2.id
GROUP BY t2.investor_id
ORDER BY t1.last_name
You can use GROUP_CONCAT and SUBSTRING_INDEX together
SELECT I.*
, SUBSTRING_INDEX(GROUP_CONCAT(L.amount ORDER BY L.id DESC), ',', 1) AS LastAmount
FROM tbl_investors AS I
LEFT JOIN tbl_investors_ledgers AS L
ON L.investor_id = I.id
GROUP BY I.id
ORDER BY I.last_name
Here a demo from SQLFiddle, many thanks to #zakhefron :)
Try this;)
SELECT t1.*, t2.*
FROM tbl_investors t1
LEFT JOIN tbl_investors_ledger t2
ON t1.id = t2.investor_id
INNER JOIN (
SELECT t.investor_id, max(t.id) as tid
FROM tbl_investors_ledger t GROUP BY t.investor_id) tt
ON tt.investor_id = t2.investor_id AND tt.tid = t2.id
ORDER BY t1.last_name
SQLFiddle DEMO
And check related OP Retrieving the last record in each group and this blog How to select the first/least/max row per group in SQL, you can find more solutions for your question.
I have a table as so...
----------------------------------------
| id | name | group | number |
----------------------------------------
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 3 | james | 2 | 2 |
| 4 | steven | 2 | 5 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
----------------------------------------
I'm running a select like so:
SELECT * FROM table WHERE number IN (2,3);
The problem im trying to solve is that I want to only grab get results from groups that have 1 or more rows of each number. For instance the above query is returning id's 1-2-3-5-6, when I'd like the results to exclude id 3 since the group of '2' can only return 1 result for the number of '2' and not for BOTH 2 and 3, since there's no row with the number 3 for the group 2 i'd like it to not even select id 3 at all.
Any help would be great.
Try it this way
SELECT *
FROM table1 t
WHERE number IN(2, 3)
AND EXISTS
(
SELECT *
FROM table1
WHERE number IN(2, 3)
AND `group` = t.`group`
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
)
or
SELECT *
FROM table1 t JOIN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
) q
ON t.`group` = q.`group`;
or
SELECT *
FROM table1
WHERE `group` IN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
);
Sample output (for both queries):
| ID | NAME | GROUP | NUMBER |
|----|-------|-------|--------|
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
Here is SQLFiddle demo
On this, you can approach from a fun way with multiple joins for what you WANT qualified, OR, apply a prequery to get all qualified groups as others have suggested, but readability is a bit off for me..
Anyhow, here's an approach going through the table once, but with joins
select DISTINCT
T.id,
T.Name,
T.Group,
T.Number
from
YourTable T
Join YourTable T2
on T.Group = T2.Group AND T2.Group = 2
Join YourTable T3
on T.Group = T3.Group AND T3.Group = 3
where
T.Number IN ( 2, 3 )
So on the first record, it is pointing to by it's own group to the T2 group AND the T2 group is specifically a 2... Then again, but testing the group for the T3 instance and T3's group is a 3.
If it cant complete the join to either of the T2 or T3 instances, the record is done for consideration, and since indexes work great for joins like this, make sure you have one index for your NUMBER criteria, and another index on the (GROUP, NUMBER) for those comparisons and the next query sample...
If doing by more than this simple 2, but larger group, prequery qualified groups, then join to that
select
YT2.*
from
( select YT1.group
from YourTable YT1
where YT1.Number in (2, 3)
group by YT1.group
having count( DISTINCT YT1.group ) = 2 ) PreQualified
JOIN YourTable YT2
on PreQualified.group = YT2.group
AND YT2.Number in (2,3)
Maybe this,if I understand you
SELECT id FROM table WHERE `group` IN
(SELECT `group` FROM table WHERE number IN (2,3)
GROUP BY `group`
HAVING COUNT(DISTINCT number)=2)
SQL Fiddle
This will return all ids where BOTH numbers exist in a group.Remove DISTINCT if you want ids for groups where just one numbers is in.