Given
------------------------------
|id | val1 | val2 | date |
______________________________
1 10 2 1990-10-02
2 10 3 1990-10-02
3 1 1 1990-10-02
4 21 1 1990-10-02
5 30 3 1990-10-02
6 30 1 1990-10-02
I want to have in results the row with id 3 and 4 because they have only one val1 if we group by val1.
How to achieve this?
SELECT DISTINCT COUNT(*) WHERE
You can use group by and having for this:
select t.*
from t
group by val1
having count(*) = 1;
In general, I am opposed to having an aggregation query with unaggregated columns in the select. However, it is fine in this case because the count(*) guarantees that there is only one matching row.
Note: this will not work in other databases.
SELECT DISTINCT x.*
FROM my_table x
LEFT
JOIN my_table y
ON y.id <> x.id AND y.val1 = x.val2
WHERE y.id IS NULL;
Related
I have a query where I want to count the values of 3 columns s, s2 and s3 and use Group By the values of column s?
So far i have made this db-fiddle
This will give me the output
1 - count 3
2 - count 3
4 - count 4
This is almost correct but I also want to include the Where clause correct so the count will only be where season = '2018/2019' and round = 34.
The wanted output must be:
1 - count 3
2 - count 2
4 - count 2
Any idea how to edit this query so the Where clause will work in the counted values?
Kinds regards,
Arie
You have to expand the unioned queries to include season and round and add conditions in the where clause:
SELECT t.s, COUNT(*) as count FROM (
SELECT s, season, round FROM tablename UNION all
SELECT s2, season, round FROM tablename UNION all
SELECT s3, season, round FROM tablename
) as t
WHERE
t.s IN (
SELECT s FROM tablename
WHERE season = '2018/2019'
AND round = 34
AND s is not null
)
AND t.season = '2018/2019'
AND t.round = 34
AND t.s is not null
GROUP BY t.s
ORDER BY count DESC, t.s
See the demo.
Results:
| s | count |
| --- | ----- |
| 1 | 3 |
| 2 | 2 |
| 4 | 2 |
You should filter the rows for each table in union
SELECT t.s, COUNT(*) as count FROM (
SELECT s
FROM tablename
WHERE season = '2018/2019' and round = 34
UNION all
SELECT s2
FROM tablename
WHERE season = '2018/2019' and round = 34
UNION all
SELECT s3
FROM tablename
WHERE season = '2018/2019' and round = 34
) as t
GROUP BY t.s
ORDER BY count DESC
I would like your assistance in solving an issue which I am battling now for days without even coming close to a solution. Unfortunately, I have already posted my issue and was not able to make any improvement with the suggestion delivered.
What I would like to achieve is somewhat attained by GROUP BY and HAVING with the possibility of CASE WHEN but whatever I do I am not getting to what I desire.
What I want to achieve is a GROUP BY only when the contents of the group exceed 3 rows and leave the individual items i.e. not grouped when group is less than or equal to three.
EXAMPLE
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
2 DESC2 2 2 4
3 DESC3 2 2 4
4 DESC4 2 2 4
5 DESC5 1 1 2
6 DESC6 1 1 2
GROUP BY will be through VAL1, VAL2, VAL 3 through the following
SELECT * FROM TABLE1 GROUP BY VAL1,VAL2,VAL3
This will yield the following:
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
5 DESC5 1 1 2
However what I need is the following:
ID DESC VAL1 VAL 2 VAL 3
1 DESC1 2 2 4
5 DESC5 1 1 2
6 DESC6 1 1 2
Can this be achieved with GROUP BY, what I think of is subquery but I cannot manage. Your assistance will be very much appreciated.
DBMS is MySQL.
Try this one. It might require some minor tweaks, as I didn't test it. But i think you will get the idea.
Select *
from table1
where md5(concat(val1,val2,val3)) in (
SELECT md5(concat(val1,val2,val3))
FROM TABLE1
GROUP BY VAL1,VAL2,VAL3
having count(*) > 3)
group by VAL1,VAL2,VAL3
union
Select *
from table1
where md5(concat(val1,val2,val3)) not in (
SELECT md5(concat(val1,val2,val3))
FROM TABLE1
GROUP BY VAL1,VAL2,VAL3
having count(*) > 3)
With UNION ALL, for the 2 different cases:
select t.* from tablename t inner join (
select min(id) minid
from tablename
group by val1, val2, val3
having count(*) > 3
) g on g.minid = t.id
union all
select * from tablename t
where (
select count(*) from tablename
where val1 = t.val1 and val2 = t.val2 and val3 = t.val3
) <= 3
See the demo
If you are using MySQL 8.0, you can achieve this simply with window functions COUNT() and ROW_NUMBER():
SELECT id, descr, val1, val2, val3
FROM (
SELECT
t.*,
COUNT(*) OVER(PARTITION BY val1, val2, val3) cnt,
ROW_NUMBER() OVER(PARTITION BY val1, val2, val3 ORDER BY id) rn
FROM mytable t
) x WHERE cnt < 3 OR rn = 1
ORDER BY id
In the inner query, cnt indicates how many records have the same val1, va2, val3 as the current one. rn assigns a rank to each record within groups of records having the same val1, va2, val3. The outer query then uses these two pieces of information to filter the relevant records.
Demo on DB Fiddle:
| id | descr | val1 | val2 | val3 |
| --- | ----- | ---- | ---- | ---- |
| 1 | DESC1 | 2 | 2 | 4 |
| 5 | DESC5 | 1 | 1 | 2 |
| 6 | DESC6 | 1 | 1 | 2 |
I have a table similar to: (There are actually many more rows.)
user_id | text
---------------------------
1 | a
1 | b
2 | c
3 | d
3 | e
4 | f
4 | g
4 | h
4 | i
5 | j
5 | k
5 | l
6 | m
I want to know how many users appeared more than once, and how many users appeared more than twice among them.((4, 2) for above table)
Now I'm using this query, but I have to run it two times after changing the number to 2.
SELECT COUNT(*)
FROM (
SELECT NULL
FROM my_table
GROUP BY user_id
HAVING COUNT(*) > 1
) T1
Because table is so big, it takes a lot of time. Can I handle these two cases in one Query?
You can do that in one query by summing the counts:
SELECT SUM(count > 1) AS more_than_once,
SUM(count > 2) AS more_than_twice
FROM (SELECT COUNT(*) AS count
FROM my_table
GROUP BY user_id
HAVING count > 1) t
Output:
more_than_once more_than_twice
4 2
Demo on dbfiddle
try like this mate
SELECT COUNT(*)
FROM (
SELECT NULL
FROM my_table
GROUP BY user_id
HAVING COUNT(*) > 1
) T1 WHERE COUNT(*) > 2
SELECT SUM(v.gt1) AS cnt_gt_1
, SUM(v.eq3) AS cnt_eq_2
, SUM(v.gt2) AS cnt_gt_2
FROM ( SELECT COUNT(*) > 1 AS gt1
, COUNT(*) = 2 AS eq2
, COUNT(*) > 2 AS gt2
FROM mytable t
GROUP
BY t.user_id
HAVING COUNT(*) > 1
) v
For performance of the inline view query, we want an index with user_id as the leading column... e.g.
... ON my_table (user_id)
Say I have a table as follows:
| id | value |
--------------
| 1 | 6 |
| 2 | 8 |
| 3 | 5 |
| 4 | 12 |
| 5 | 6 |
I want to return the two rows for which added together will equal a certain value
e.g. I want to get 2 rows where the total is 18, so in the above table it should return:
| id | value |
--------------
| 1 | 6 |
| 4 | 12 |
...as the sum of values here is 18. It shouldn't match on the other 3 rows even if they add up to the total as it can only be sum of 2 rows in this case.
Also, if there are multiple pairs that add up to the required value, it should only return the first match.
edit:
Came up with this which seems to do the trick but I'm not sure it's the best method
SELECT *, (t1.value+t2.value) AS total
FROM test t1, test t2
WHERE t1.id != t2.id
HAVING total = 18
LIMIT 1
Here's something similar to what you're after...
SELECT x.id x_id
, y.id y_id
FROM my_table x
JOIN my_table y
ON y.id > x.id
WHERE x.value + y.value = 18
ORDER
BY x.id
, y.id
LIMIT 1;
MySQL doesn't really lend to such queries. The only [admitedly god aweful] solution I can think of is to self-join the table to get the two records, and then put this join in a CTE and use union all to get the two records on separate rows:
WITH summer AS (
SELECT a.id AS a_id, a.value AS a_value, b.id AS b_id, b.value AS b_value
FROM mytable a
JOIN mytable b ON a.id <> b.id AND a.value + b.value = 18
ORDER BY a.id, b.id
LIMIT 1
)
SELECT a_id, a_value
FROM summer
UNION ALL
SELECT b_id, b_value
FROM summer
Here is a simple query for doing it:
SELECT
number1.id, number2.id
FROM
number AS number1
JOIN
number AS number2 ON number1.value + number2.value = 18
AND number2.id > number1.id
I got a table like this:
id | column_a | column_value
1 | x | 5
2 | y | 7
3 | z | 4,7
4 | x | 3,6
5 | y | 2
6 | w | 5,8,9,11
I would like to get back column_value from latest record in each groups AND a count number of rows in the groups.
So the result should be this:
count(id) | column_value
2 | 3,6
2 | 2
1 | 4,7
1 | 5,8,9,11
I tried to reach this on the following two path:
select count(id), column_value
from table
group by column_a
This version get back the first records from the groups so its not ok for me.
select count(id), column_value
from table
where id in (select max(id)
from table
group by column_a)
This version also wrong because count cannot works well without group by.
I cannot figure it out how can I combine two versions advantages.
Any help is appreciated.
Try this
Select cnt, column_value
from tst t inner join (
Select column_a, count(id) cnt, max(id) as max_id
from tst
group by column_a ) x on (t.column_a= x.column_a and t.id = x.max_id)
order by cnt desc