Search within GROUP_CONCAT - mysql

I am executing this SQL from a big result of rows
SELECT userid, group_concat(locationid)
FROM user_location
group by userid
having group_concat(locationid) = 10
userid locationid
--------- ----------
894801 10,10,10,10,10,10,10,10,10,10,10,10
898356 10,10,11,10
900424 10,10,13,12,12,12,12
902123 10
904910 10,10
907922 10,10,10
912587 10,12,12
930319 10
Now, I want only those locationid rows where the value = 10 and no other value
Desired Output:
userid locationid
--------- ----------
894801 10,10,10,10,10,10,10,10,10,10,10,10
902123 10
904910 10,10
907922 10,10,10
930319 10
I explored and found find_in_set() but no use here

Don't use the result from group_concat(). Just use a simple having clause:
SELECT userid, group_concat(locationid)
FROM user_location
GROUP BY userid
HAVING SUM(locationid = 10) = COUNT(*)
The SUM() counts the number of values that are equal to 10. The = COUNT(*) simply says that all are 10.
You can also do this by being sure that no values are not 10:
HAVING SUM(locationid <> 10) = 0

SELECT * FROM user_location WHERE userid not in (select userid from user_location where locationid<>10)
group by userid having locationid=10;
Try this.. It's working

Related

Sorting by frequency in MySQL/SQL

Is there way of sorting by frequency that a value occurs? If a value appears in multiple rows, would we just use the WHERE clause? Is it just about making the query more specific?
As a simple example:
CREATE TABLE mytable
( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
, val VARCHAR(15) NOT NULL
);
INSERT INTO mytable (id, val) VALUES
(1,'one')
,(2,'prime')
,(3,'prime')
,(4,'square')
,(5,'prime')
,(6,'six')
,(7,'prime')
,(8,'cube')
,(9,'square')
;
We can write a simple query to return the rows
SELECT t.val
, t.id
FROM mytable t
ORDER BY t.val
But what query do we use to get the most frequently occurring values listed first? To return a result like this:
freq val id
---- ------ --
4 prime 2
4 prime 3
4 prime 5
4 prime 7
2 square 4
2 square 9
1 cube 8
1 one 1
1 six 6
where freq is the frequency (the count of the number of rows) that a value appears in the val column. The value 'prime' appears in four rows, so freq has a value of 4.
What MySQL SELECT query would I use to return a result like this?
Try this:
SELECT A.Freq , A.val , A.id
FROM ( SELECT COUNT(*) AS Freq , val , id
FROM mytable
GROUP BY val , id ) A
ORDER BY Freq DESC ;
EDIT:
As suggested by spencer7593, the id is defined as auto-increment in the table and hence the GROUP BY should not include it. Still, if that would be the case, it is not clear how the result could be as shown. I'm adding here an alternative SELECT that, supposedly, should yield the shown output:
SELECT B.Freq , A.val , A.id
FROM mytable A
INNER JOINT ( SELECT val , COUNT(*) AS Freq
FROM mytable
GROUP BY val) B
ON A.val = B.val
ORDER BY B.Freq DESC ;
[NOTE: This was NOT tested!!!!]

SELECT value BEFORE max mysql

so, i have this table generated annually :
+----+------+
| id | name |
+----+------+
| 1 | 20162|
| 2 | 20162|
| 3 | 20171|
| 4 | 20171|<<<||| "how do i get this bfore max value"
| 5 | 20172|
| 6 | 20172|
+----+------+
If i query :
SELECT name FROM table WHERE where name=(SELECT max(name))
The result is 20172
How do i get the value before that (20171)?
This will get second max.
SELECT *
FROM table
WHERE name NOT IN (SELECT MAX(name) FROM table )
ORDER BY id DESC LIMIT 1
You can do the little trick:
SELECT name FROM table ORDER BY name DESC LIMIT 1,1
If you want a portable solution (since the above will only work in MySQL probably):
SELECT name FROM table t1 where
1 = (SELECT count(distinct name)
from table t2
where t2.name > t1.name )
This selects the name which has exactly one other name which is greater than it. It will have issues when e.g. all values are the same but that may actually be the intention sometimes.
Also you can try this:
SELECT name
FROM (SELECT DISTINCT name FROM yourtable) TMP
ORDER BY name DESC LIMIT 1,1
how about this:
select b.second_id,b.name from
(select id, max(name) as max from tbl_max) as a
LEFT JOIN
(select id as second_id, name from tbl_max ) as b
on a.id <> second_id where name < a.max order by name desc limit 1;
Another solution much better:
set #max= 0;
select max(name) into #max from tbl_max;
select * from tbl_max where name < #max ORDER BY id desc limit 1
it return a result of
4 20171
If you want Max(name)
SELECT id,MAX(name) FROM table
WHERE name < (SELECT MAX(name) FROM table )
or
SELECT id,MAX(name) FROM table
WHERE name <> (SELECT MAX(name) FROM table )
And there is an article for Find nth high value
(as Question changed later, this tricks is not useful for this problem)
can you use this simple order by ?
SELECT * FROM tablename
group by name
order by name desc
limit 1,1
if you have multiple equal values in MAX(name) you need group by, even this query is not general solution!
You can try below code.It will give you nth highest record.
SELECT NAME FROM table ORDER BY name DESC LIMIT n,1
Hope this will helps
SELECT DISTINCT name FROM table ORDER BY name DESC LIMIT 1,1;
The LIMIT clause accepts two values, an offset and a count. When only 1 value is provided, it assumes the offset is 0
DISTINCT is necessary as you have duplicate values for name. If this was unintentional, it's not needed.
Example at http://sqlfiddle.com/#!9/ea6e2/2

In clause with And operation

I have records like this....
oid id
35 1
43 1
46 1
43 2
49 2
50 3
51 3
52 4
I have id=1 and 2 . I want those results which belong to both the both the ids(1,2) only.
i.e - o/p = recodrds of object_id = 43 because it is belonging to both 1 and 2.
if I use in operator then it is giving all the records (performing OR operaion)
This is a generic, fast solution to this kind of problems.
Get all IDs (in this case oid values) that staisfy our condition:
select oid from MyTalbe
where id in (1,2)
group by oid
having count (distinct id) >1
Select rows where IDs ('oid` column) IN list of IDs we need:
select oid, id from Mytable
where oid in
(select oid from MyTalbe
where id in (1,2) -- This is the same as: where id =1 or id=2
group by oid
having count (distinct id) >1
)
You can use the IN operator but then use a GROUP BY with a HAVING clause to return only those rows with a DISTINCT count of 2:
select oid
from yourtable
where id in (1,2)
group by oid
having count(distinct id) = 2;
--^ change this number to the count of ids in IN clause
See SQL Fiddle with Demo
Try this
SELECT t.oid FROM table1 t
WHERE t.oid IN (SELECT oid FROM table1 t1 WHERE t1.oid=t.oid AND t1.id = 1)
AND t.oid IN (SELECT oid FROM table1 t1 WHERE t1.oid=t.oid AND t1.id = 2)
GROUP BY oid

Sort varchar datatype with numeric characters

I have a varchar column that needs to be sorted by the number included in it. The data is similar to:
Group 1
Group 10
Group 11
Group 12
Group 13
Group 14
Group 15
Group 16
Group 17
Group 18
Group 19
Group 2
Group 20
Group 3
Group 4
Group 5
Group 6
Group 7
Group 8
Group 9
Test Group
I want the output like this where the value is sorted by the number.
Group 1
Group 2
Group 3
Group 4
Group 5…..
TRY like below, It will help you..
SELECT ColumnName FROM TableName
ORDER BY CONVERT(INT, Replace(ColumnName, 'Group',''))
SQL Fiddle : http://sqlfiddle.com/#!3/e14a6/7
Another Way
SELECT ColumnName FROM TableName
ORDER BY LEN(ColumnName),ColumnName
SQL Fiddle : http://sqlfiddle.com/#!3/e14a6/6
Another Way
SELECT ColumnName FROM TableName order by
case when
PATINDEX('%[^0-9]%',ColumnName) = 0
THEN
data
ELSE
cast(Left(ColumnName,PATINDEX('%[^0-9]%',ColumnName)-1) as int)
END
SQL Fiddle : http://sqlfiddle.com/#!3/14eb5/2
Another Way
Here i have add another solution by using Common Table Expression Try this...
with tempCTE(Data, pos)
as
(select data, Patindex('%[0-9]%', data) from sample),
tempCTE2(name, num)
as
(select SUBSTRING(data, 0, pos) name , cast(SUBSTRING(data, pos , LEN(data)) as int) num from tempCTE)
select name + CAST(num as varchar(10)) num1 from tempCTE2 order by name, num asc
SQL Fiddle : http://sqlfiddle.com/#!3/14eb5/3

Count duplicates records in Mysql table?

I have table with, folowing structure.
tbl
id name
1 AAA
2 BBB
3 BBB
4 BBB
5 AAA
6 CCC
select count(name) c from tbl
group by name having c >1
The query returning this result:
AAA(2) duplicate
BBB(3) duplicate
CCC(1) not duplicate
The names who are duplicates as AAA and BBB. The final result, who I want is count of this duplicate records.
Result should be like this:
Total duplicate products (2)
The approach is to have a nested query that has one line per duplicate, and an outer query returning just the count of the results of the inner query.
SELECT count(*) AS duplicate_count
FROM (
SELECT name FROM tbl
GROUP BY name HAVING COUNT(name) > 1
) AS t
Use IF statement to get your desired output:
SELECT name, COUNT(*) AS times, IF (COUNT(*)>1,"duplicated", "not duplicated") AS duplicated FROM <MY_TABLE> GROUP BY name
Output:
AAA 2 duplicated
BBB 3 duplicated
CCC 1 not duplicated
For List:
SELECT COUNT(`name`) AS adet, name
FROM `tbl` WHERE `status`=1 GROUP BY `name`
ORDER BY `adet` DESC
For Total Count:
SELECT COUNT(*) AS Total
FROM (SELECT COUNT(name) AS cou FROM tbl GROUP BY name HAVING cou>1 ) AS virtual_tbl
// Total: 5
why not just wrap this in a sub-query:
SELECT Count(*) TotalDups
FROM
(
select Name, Count(*)
from yourTable
group by name
having Count(*) > 1
) x
See SQL Fiddle with Demo
The accepted answer counts the number of rows that have duplicates, not the amount of duplicates. If you want to count the actual number of duplicates, use this:
SELECT COALESCE(SUM(rows) - count(1), 0) as dupes FROM(
SELECT COUNT(1) as rows
FROM `yourtable`
GROUP BY `name`
HAVING rows > 1
) x
What this does is total the duplicates in the group by, but then subtracts the amount of records that have duplicates. The reason is the group by total is not all duplicates, one record of each of those groupings is the unique row.
Fiddle: http://sqlfiddle.com/#!2/29639a/3
SQL code is:
SELECT VERSION_ID, PROJECT_ID, VERSION_NO, COUNT(VERSION_NO) AS dup_cnt
FROM MOVEMENTS
GROUP BY VERSION_NO
HAVING (dup_cnt > 1 && PROJECT_ID = 11660)
I'm using this query for my own table in PHP, but it only gives me one result whereas I'd like to the amount of duplicate per username, is that possible?
SELECT count(*) AS duplicate_count
FROM (
SELECT username FROM login_history
GROUP BY username HAVING COUNT(time) > 1
) AS t;