How to get all used values in columns in mysql? - mysql

I have a MySQL table with columns and values like this:
Column "A": 1, 5, 3, 2, 3, 1, 4, 5, ...
Column "B": 11, 15, 10, 12, 13, 14, 15, 10, 11, ...
Column "C": .... etc.
There is multiple columns in table with repeating numeric values.
I want to find out unique values in each column. So for column "A" it would return 1,2,3,4,5.
Currently I am using this query for one column:
SELECT concat(A) FROM table GROUP BY A;
But I don't know how to do it for multiple columns

If it's a small enough set of values, you can use the GROUP_CONCAT aggregate function, with the DISTINCT keyword
For example:
SELECT GROUP_CONCAT(DISTINCT a ORDER BY a) AS a_values
, GROUP_CONCAT(DISTINCT b ORDER BY b) AS b_values
, GROUP_CONCAT(DISTINCT c ORDER BY c) AS c_values
FROM mytable
The length of the string returned by GROUP_CONCAT is limited by the max_group_concat_len variable (it's in the reference) and I think the max_allowed_packet also comes into play.
Compare the length of the string returned to max_group_concat_len to see if it's shorter, to know that the return string hasn't been silently truncated.
If you want to combine all of those values together, into a single distinct list, you could do something like this:
SELECT GROUP_CONCAT(DISTINCT val ORDER BY val) AS col_values
FROM ( SELECT a AS val FROM mytable
UNION
SELECT b FROM mytable
UNION
SELECT c FROM mytable
) v
EDIT
I was confused by the use of the CONCAT function in the query, and misread the specification. The queries above return a single row, and returns a result that looks EXACTLY like what OP specified:
1,2,3,4,5,...
If we want to return each value on a separate row, a result that looks like this:
val
---
1
2
3
4
5
Then the query from Tim3880's answer does that, but the outer query isn't really necessary.
I'd want to add an ORDER BY, and actually write the query like this:
(SELECT a AS val FROM mytable)
UNION
(SELECT b AS val FROM mytable)
UNION
(SELECT c AS val FROM mytable)
ORDER BY 1
EDIT
Added SQL Fiddle showing how I interpret the specification (table, columns, exemplar values), and results from SQL statements above... one statement returning distinct values as individual rows (query immediately above), and a statement returning a comma separated list (the first query in my answer.)
SQL Fiddle Example HERE http://sqlfiddle.com/#!9/3d61c/1
If we want to identify which column(s) a value appears in
SELECT v.val
, GROUP_CONCAT(DISTINCT v.col ORDER BY v.col) AS in_cols
, MAX(v.col='a') AS in_col_a
, MAX(v.col='b') AS in_col_b
, MAX(v.col='c') AS in_col_c
FROM (
SELECT a AS val, 'a' AS col FROM mytable
UNION
SELECT b AS val, 'b' AS col FROM mytable
UNION
SELECT c AS val, 'c' AS col FROM mytable
) v
GROUP BY v.val
ORDER BY v.val

If your query works for A, then you can do it for A, B, C using this:
SELECT A FROM
(
SELECT A FROM table
UNION
SELECT B FROM table
UNION
SELECT C FROM table
) e
as long as the three columns have compatible types.

Related

How can I query my table to group it by 2 fields in mySQL?

I'm stuck.
I'm trying to query one of my tables to obtain the maximum 'canister_change_date' with grouped pairs 'canister_type' and 'test_cell'.
I've put together a table with some dummy data (below) If you want the create table schema, let me know and I'll put it in the comments.
The final result would either need to have the id's or the whole row with id.
expected result (below) would have id's - 1, 2, 3, 5, 7, 8
6 should be removed as matching pair (test_cell =4, canister_type=Carbon Monoxide) and 7 to be taken as it has the later 'canister_change_date' date.
The expect result would either need to have the id's or id's and rest of fields.
Thanks!
You can use GROUP BY on multiple columns just like that
SELECT COUNT(*) FROM my_table GROUP BY column1, column2
If you want to find row with highest value of some column then you will need HAVING clause and MAX() aggregate function. You can combine them like this
SELECT max_column, column1, column2
GROUP BY column1, column2
HAVING max_column = MAX(max_column)
This example assumes you want to find highest value of max_column for each unique pair of column1 and column2
With NOT EXISTS:
select t.* from tablename
where not exists (
select 1 from tablename
where test_cell = t.test_cell and canister_type = canister_type
and canister_change_date > t.canister_change_date
)
or if your version of MySql is 8.0+ and supports window functions:
select t.* from (
select *,
row_number() over (partition by test_cell, canister_type order by canister_change_date desc) rn
from tablename
) t
where t.rn = 1

Order by FIELD along with subquery?

I want to order the query results by specific values.
Seems like I can use this:
SELECT
column
FROM
table
ORDER BY
IF(
FIELD(
id,
3,1,2
) = 0,
1,
0
) ASC,
FIELD(
id,
3,1,2
)
My problem is that 3,1,2 comes from another table column. Replacing 3,1,2 with (SELECT column from...) is not working properly. Because the SELECT returns the result as "3,1,2" and not as 3,1,2
I can also extract 3,1,2 one by one, but in this case i get error Subquery returns more than 1 row.
What's the solution here ?
Suppose that the statement that returns the values 3, 1, 2 is something like this:
SELECT somecolumn FROM sometable ORDER BY someothercolumn
then you can use GROUP_CONCAT() to create a comma separated string that contains these values:
SELECT GROUP_CONCAT(somecolumn ORDER BY someothercolumn) col FROM sometable
and then use FIND_IN_SET() instead of FIELD():
SELECT t.column
FROM table t
CROSS JOIN (SELECT GROUP_CONCAT(somecolumn col ORDER BY someothercolumn) FROM sometable) s
ORDER BY
SUBSTRING_INDEX(t.id, s.col) = 0,
SUBSTRING_INDEX(t.id, s.col)
I hope that I understood the logic that you want to apply to sort the table with your ORDER BY clause.

Get list of IDs not present in table

Say I have a list of ids, e.g. (1, 3, 9, 2, 4, 86), and a table with a column id. I want to find all of the numbers in my list where there is not a matching row.
i.e. if the mysql table was like this:
id letter
1 a
2 b
3 c
4 d
5 e
6 f
7 g
And I have the list (1, 3, 9, 2, 4, 86), I want a query that will return (9, 86).
The only thing I can think of, is to build a really big virtual table, like:
select 1 as n union select 3 as n union select 9 as n union ....
Which I can then join against. Is there a better way? I would like to be able to do this all within mysql. As a side note (although I don't expect it to be relevant), my table has around 10,000 rows, and the list I'm using has ~100 numbers in it.
You have to first create a table that will contain the elements of the LIST
i.e (1, 3, 9, 2, 4, 86)
create table t
(
num int
)
insert into t
values
(1),(3),(9),(2),(4),(86)
Now you can use NOT IN
SELECT num
FROM t
WHERE num not in (select id from letter_table);
SQL Fiddle
From Comments.
Edit:
There is a way in which you don't have to create a table
select N from
(select 1 as N
union all
select 3 as N
union all
select 9 as N
union all
select 2 as N
union all
select 4 as N
union all
select 86 as N)t1
where t1.N
not in (select id from letter_table)
Please refer the New SQL Fiddle.
I think OP want's the Edited Part.
P.S. Make Sure table t1 doesn't exists in your DB
Create a table which contains IDs and than you can do it eaasily. See a demonstration here
SELECT
S.id,
'' AS `letter`
FROM sequence S
WHERE S.id NOT IN(SELECT
id
FROM mytable)
SQL Fiddle Demo
Assuming you use the temp table or the UNION method in #Luv's answer, consider replacing the NOT IN with an outer join as it'll likely perform better (test with your actual environment & data, of course):
SELECT num
FROM t
LEFT OUTER JOIN letter_table
ON t.num = letter_table.id
WHERE letter_table.id IS NULL;
If you use the UNION method, replace FROM t with FROM ([big UNION here]) t.

mysql count of distinct records after match

Given table 'x':
Source Dest Type
A B 2
A D 2
B C 2
Now I want the total count of Source and destination removing the matching ones..
Example of above one: For type 2, Count will be 4, i.e. Count(A,B,C,D)
I tried this:
select Count(distinct Source), Count(distinct destination),Count(distinct source)+Count( distinct destination),Type
from X
where Type=2 and Src NOT IN (select destination
from X
where Type=2)
I need to simplify this query for all the types.
Let me know if there is any way I could do it.
Thanks!
SELECT COUNT(DISTINCT a), Type
FROM (
SELECT DISTINCT Source AS a, Type
FROM x
UNION ALL
SELECT DISTINCT Dest AS a, Type
FROM x
)
GROUP By Type
The inner union query converts your two separate columns into a single column, then the outer query takes that union'd result and counts up the individual values, grouped by Type.
An inefficient method would be to do the following
SELECT
distinctMatches.type AS type,
COUNT(DISTINCT distinctMatches.name) AS quantity
FROM
(
(
SELECT DISTINCT
type,
source AS name
FROM x
)
UNION DISTINCT
(
SELECT DISTINCT
type,
destination AS name
FROM x
)
) AS distinctMatches
GROUP BY distinctMatches.type
This would give with your example data 1 row with type 2 and quantity 4
In an ideal world I'd look at the database design as it feels as if it should be split into multiple tables i.e. one for sources (as you seem to be grouping "source" and "destination" which indicates they are effectively the same item). If you are able to normalise the design further this type of query will be easier to do more efficiently
try this:
SELECT COUNT(xxx.a) as TotalCount
FROM
(SELECT source a, type FROM tableX
UNION
SELECT dest a, type FROM tableX) xxx
WHERE xxx.Type = 2

two slightly different queries into one - use a conditional var?

Instead of executing 2 slightly different sql statements to get a total of 10 results can it be done with just one select?
e.g
select
a
, b
, c
from mytable limit 3
select
a
, b
, LEFT(100, c )
from mytable limit 3, 10
Check out UNION syntax
(SELECT a,b,c FROM mytable LIMIT 3)
UNION
(SELECT a,b,LEFT(100, c) FROM mytable LIMIT 3, 10);
Note the parentheses - these ensure the final LIMIT clause applies to the second query and not the whole result set.
Unless you've got a numeric key in the result which would let you use an IF to format the first n results differently, I don't think you're going to do this with a single select.
You can select all ten rows and then use a case statement to control what value is returned depending on a conditional statement you define.
set #line_total= 0;
select
a,
b,
#line_total := #line_total + 1,
(case when #line_total < 4
then c
else left(100, c) end)
from test_query limit 10;
http://dev.mysql.com/doc/refman/5.0/en/case-statement.html