How to show column name if it contains a specific value? - mysql

I'm trying to display the column name of the my table if it has the value 1
| A | B | C | D |
| 0 | 1 | 1 | 0 |
In this case i would like to get the result:
| Column |
| B |
| C |
I wrote the following query but it is not working:
SHOW COLUMNS
FROM `questions`
WHERE VALUES=`1`

If you just need a list of the columns that contain the value = 1, you should be able to use the following query:
select col
from
(
select col,
case s.col
when 'A' then A
when 'B' then B
when 'C' then C
when 'D' then D
end AS val
from yourtable
cross join
(
select 'A' AS col union all
select 'B' union all
select 'C' union all
select 'D'
) s
) s
where val = 1;
See SQL Fiddle with Demo. This uses a virtual table with your column names (A, B, etc) to unpivot your columns and then you just return only the column names that contain a value of 1. Credit for this technique goes to #Andriy M.

Related

not having query in mysql?

If I have a table like this:
id column1 column2
1 A A
1 B B
1 C A
2 B A
2 B C
2 C C
3 D C
3 B D
3 E D
what I want is counting distinct ids which don't contain column1=A or column2=A.
From my table, count(distinct(id)) should be 1 because id 1 has a rows contain column1=A, column2=A and id 2 , column2=A. so id 3 is the only id which rows don't contain column1 != A or column2 != A.
Which query should I use?
This might help you;)
SQL Fiddle
MySQL 5.6 Schema:
CREATE TABLE SO_TEST (
id int,
column1 char(2),
column2 char(2)
);
INSERT SO_TEST VALUES
(1,'A','A'),
(1,'B','B'),
(1,'C','A'),
(2,'B','A'),
(2,'B','C'),
(2,'C','C'),
(3,'D','C'),
(3,'B','D'),
(3,'E','D');
Query 1:
SELECT COUNT(1) AS RESULT
FROM (
SELECT id, GROUP_CONCAT(CONCAT(CONCAT(column1,','),column2)) STR FROM SO_TEST GROUP BY id
) TMP
WHERE FIND_IN_SET('A',TMP.STR) = 0
Okay, let's explain it.
In subquery, I've retrieved all column1, column2 value by group id and concat them, and it will return us follow results and you can try it in sqlfiddle.
+----+-------------+
| id | STR |
+----+-------------+
| 1 | A,A,B,B,C,A |
| 2 | B,A,B,C,C,C |
| 3 | D,C,B,D,E,D |
+----+-------------+
So In main query, I used FIND_IN_SET(param1, param2) in WHERE clause, this function will return us the index of param1 in param2(param2's every element must be separated by a comma), and if param1 not in param2, return 0, so we could be clear about WHERE clause.
At last count(1) will help us get what we want.
Results:
| RESULT |
|--------|
| 1 |
From what I understand here is distinct IDs
select count(distinct id) from test2
where col1 !='A' AND col2 !='A'
OUTPUT
+-------------------+
| COUNT(DISTINCTID) |
+-------------------+
| 3 |
+-------------------+
You can do something like this, that will return you the count of rows grouped by ID when column1 is distinc to 'A' and column2 is distinct to 'B':
SELECT COUNT(*) as cont
FROM test
WHERE column1 != 'A' AND column2 != 'A'
GROUP BY id
In your example that will return you:
id cont
1 1
2 2
3 3
Because id 1 has only (B, B) as a good value, id 2 has (B, C) and (C, C) and id 3 has all as a good value.
Hope it will help you.

Count number of rows that are at the minimum of a group MySQL

I have a table that contains all the distinct names from another table, and then a column that holds the minimum value that the name received. For example, the table looks like this:
table1
Name | min_value
a | 1
b | 2
c | 4
The original table looks like this:
table2
Name | value
a | 1
b | 2
c | 4
a | 2
c | 8
a | 1
I want to return the number of times that the minimum value occurs within the original table. So, in this example it would return something like this:
output_table
Name | times_at_min
a | 2
b | 1
c | 1
Any help would be appreciated, thanks in advance.
One way to do it is:
SELECT m.Name,
min_value,
COUNT(CASE WHEN m.value = min_value THEN 1 END) As times_at_min
FROM mytable AS m
INNER JOIN (
SELECT Name,
MIN(value) AS min_value
FROM mytable
GROUP BY Name ) AS g
ON m.Name = g.Name
GROUP BY Name
In a subquery you select MIN(value) per Name. Joining with the derived table of this subquery, you can perform conditional aggregation so as to calculate the number of times the minimum value appears in the original table.
Fiddle demo here

A row for each column as MySQL select result [duplicate]

I'm probably not seeing things very clear at this moment, but I have a table in MySQL which looks like this:
ID | a | b | c
1 | a1 | b1 | c1
2 | a2 | b2 | c2
For some reason (actually a join on another table - based on ID, but I think if someone can help me out with this part, I can do the rest myself), I needed those rows to be like this instead:
1 | a1 | a
1 | b1 | b
1 | c1 | c
2 | a2 | a
2 | b2 | b
2 | c2 | c
So basically, I need to view the rows like: ID, columntitle, value
Is there any way to do this easily?
You are trying to unpivot the data. MySQL does not have an unpivot function, so you will have to use a UNION ALL query to convert the columns into rows:
select id, 'a' col, a value
from yourtable
union all
select id, 'b' col, b value
from yourtable
union all
select id, 'c' col, c value
from yourtable
See SQL Fiddle with Demo.
This can also be done using a CROSS JOIN:
select t.id,
c.col,
case c.col
when 'a' then a
when 'b' then b
when 'c' then c
end as data
from yourtable t
cross join
(
select 'a' as col
union all select 'b'
union all select 'c'
) c
See SQL Fiddle with Demo
It took a long time coming, but MySQL version 8.0.14 finally added support for lateral joins - the official terminology is lateral derived tables.
This is a very powerful feature, that comes handy in multiple situations, including unpivoting table columns to rows.
You can phrase the query as follows:
select t.id, x.*
from mytable t
cross join lateral (
select a, 'a'
union all select b, 'b'
union all select c, 'c'
) as x(col1, col2)
It may look like this is not a big difference compared to the typical cannonical solution - after all, we are still using union all within the lateral derived table... But don't get it wrong: this query scans the table only once, as opposed to the other approach, which requires one scan for each column to unpivot. So this is more efficient - and the performance gain increases dramatically as the table goes bigger and/or more columns need to be unpivoted.
Bottom line: if you are running MySQL 8.0.14 or higher, just use this technique. From that version onwards, this is the canonical way to unpivot in MYSQL.
Demo on DB Fiddle:
Sample data:
ID | a | b | c
-: | :- | :- | :-
1 | a1 | b1 | c1
2 | a2 | b2 | c2
Query results:
id | col1 | col2
-: | :--- | :---
1 | a1 | a
1 | b1 | b
1 | c1 | c
2 | a2 | a
2 | b2 | b
2 | c2 | c
Side note
MySQL 8.0.19 added support for the VALUES statement, which could help further shortening the query by removing the need to use union all in a subquery (although I don't see any performance gain here, this makes the query neater).
Unfortunately, as of version 8.0.21, this does not work yet - which might be considered a bug - but maybe will in a future version...:
select t.id, x.*
from mytable t
cross join lateral (values
row(a, 'a'),
row(b, 'b'),
row(c, 'c')
) as x(col1, col2);
Try to use UNION ALL.
SELECT ID, a, 'a'
FROM tbl
WHERE ID = 1
UNION
SELECT ID, b, 'b'
FROM tbl
WHERE ID = 2

Can grouped expressions be used with variable assignments?

I'm trying to calculate row differences (like MySQL difference between two rows of a SELECT Statement) over a grouped result set:
create table test (i int not null auto_increment, a int, b int, primary key (i));
insert into test (a,b) value (1,1),(1,2),(2,4),(2,8);
Gives
| a | b
---------
| 1 | 1
| 1 | 2
| 2 | 4
| 2 | 8
This is the simple SQL with group and max(group) result columns:
select
data.a,
max(data.b)
from
(
select a, b
from test
order by i
) as data
group by a
order by a
The obvious result is
| a | max(data.b)
-----------------
| 1 | 2
| 2 | 8
Where I'm failing is when I want to calculate the row-by-row differences on the grouped column:
set #c:=0;
select
data.a,
max(data.b),
#c:=max(data.b)-#c
from
(
select a, b
from test
order by i
) as data
group by a
order by a
Still gives:
| a | max(data.b) | #c:=max(data.b)-#c
--------------------------------------
| 1 | 2 | 2 (expected 2-0=2)
| 2 | 8 | 8 (expected 8-2=6)
Could anybody highlight why the #c variable is not updating from grouped row to grouped row as expected?
SELECT data.a
, data.b
, #c := data.b - #c
FROM (
SELECT a
, max(b) AS b
FROM test
GROUP BY a
) AS data
ORDER BY a
Example
The 'documented' solution might look like this...
SELECT x.*
, #c := b - #c c
FROM test x
JOIN
( SELECT a,MAX(b) max_b FROM test GROUP BY a ) y
ON y.a = x.a
AND y.max_b = x.b
JOIN (SELECT #c:= 0) vals;

How to find the exact group that matches to defined values?

I simplified the table so it is easier to understand.
I have a table with groups and a group exists of multiple values. Here is the table:
VALUE | GROUP
A | 1
B | 1
A | 2
C | 2
B | 3
A | 4
B | 4
A | 5
B | 5
C | 5
I want to give values to my query wich I programmatically build and find the exact group that matches to these values.
For example if I give value A and B to my query I want as a result group 1 and 4
A ---------------> null
A and B ----------> 1 and 4
A , B and C ------> 5
B ---------------> 3
A and C ----------> 2
C ----------------> null
You can use a query like the following (assuming value,group pairs unique):
select `GROUP`
from MyTable
group by `GROUP`
having count(`VALUE`) = count(case when `VALUE` IN ('a','b') then 1 end)
and count(case when `VALUE` IN ('a','b') then 1 end) = #Count;
Where ('a','b') would be the list of values you are testing for, and #Count would be the count of different values in your check set (2 in this case).
Demo: http://www.sqlfiddle.com/#!2/78def/13