not having query in mysql? - 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.

Related

Group and order rows with multiple column MySQL

I want to rows according to same column value.
Suppose this is a table
id name topic
1 A t
2 B a
3 c t
4 d b
5 e b
6 f a
I want result something like this.
id name topic
1 A t
3 c t
2 B a
6 f a
4 d b
5 e b
As you can see these are not order by topic neither by id, it sort about that topic which come first if t come first sort t first, one second a come then sort according to a then b.
if you apply ORDER BY topic it sort a b t or in DESC t b a but required result is t a b
Any suggestion ?
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,topic CHAR(1) NOT NULL
);
INSERT INTO my_table VALUES
(1,'t'),
(2,'a'),
(3,'t'),
(4,'b'),
(5,'b'),
(6,'a');
SELECT x.*
FROM my_table x
JOIN
( SELECT topic, MIN(id) id FROM my_table GROUP BY topic ) y
ON y.topic = x.topic
ORDER
BY y.id,x.id;
+----+-------+
| id | topic |
+----+-------+
| 1 | t |
| 3 | t |
| 2 | a |
| 6 | a |
| 4 | b |
| 5 | b |
+----+-------+
You can use CASE expression in ORDER BY.
Query
select * from `your_table_name`
order by
case `topic`
when 't' then 1
when 'a' then 2
when 'b' then 3
else 4 end
, `name`;

MySQL: Return all rows with same ID but filter by a different field

In my application, I have a table that identifies resources (i.e. pictures) by their id. Said resources have also been "tagged" (field1). i.e. Picture 3 in the table below is tagged with both 'A' and 'B'. Whereas Picture 1 is tagged with only 'A' and Picture 2 is tagged with only 'B'.
Here is my "tagging" table:
+--------------+
| id | field1 |
+--------------+
| 1 | A |
| 2 | B |
| 3 | A |
| 3 | B |
+--------------+
Note: The id's are neither unique nor auto-incrementing.
Problem: I want to return all pictures tagged as 'B', but I do not want to return any that are tagged as 'A'.
SELECT id from pictures
WHERE field1 = 'B';
Returns:
+-----+
| id |
+-----+
| 2 |
| 3 |
+-----+
This is not want I want, because it includes Picture 3 which is also tagged with 'A' (in the row immediately preceding [3, B] in the original table)
I want:
+-----+
| id |
+-----+
| 2 |
+-----+
here are two methods:
exists subclause:
SELECT id
from pictures as pictures1
WHERE field1 = 'B'
and not exists (
select *
from pictures as picutures2
where pictures2.id = pictures1.id
and pictures2.field1 = 'A');
left join:
Select pictures1.id
from pictures as pictures1
left join pictures as picutures2 on
pictures2.id = pictures1.id
and pictures2.field1 = 'A'
where pictures1.field1 = 'B'
and pictures2.ID is null -- this line eliminates records where the join fails; note that if you have this line, you must not put any other pictures2 references in this where clause
;
You started well with your request. Just unselect rows where field1 is A. :
SELECT id from pictures WHERE field1 = 'B' AND id NOT IN(
SELECT id from pictures WHERE field1 = 'A'
);
You can also achieve your desired result using some aggregation in a single query
select id
from table1
group by id
having sum(field1 = 'B') > 0
and sum(field1 = 'A') = 0
DEMO
SELECT id
FROM pictures
GROUP BY id
HAVING (GROUP_CONCAT(DISTINCT fuild1)) = 'B'

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

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.

Query with subquery not returning all results

I am doing the next query:
SELECT id, name, keyt
FROM table
WHERE id = (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND() LIMIT 1)
Supposing table is like this:
| id | name | keyt |
+ ------------------------- +
| 1 | Hello | 21 |
| 3 | Katzet | 1 |
| 1 | Welcome | 1 |
| 2 | Two | 21 |
| 2 | Other | 1 |
It should return one of this pairs:
Hello | Welcome (id 1 in common)
Two | Other (id 2 in common)
So, the idea is:
Get one id, which has the keyt value set to 21
Then, get all the rows with this selected id (independently of all the other keyt values)
If I do as you suggested... I would get mixed id values, and all result rows must have the same id.
SELECT x.*
FROM my_table x
JOIN
( SELECT id
FROM my_table
WHERE keyt = 21
ORDER
BY RAND() LIMIT 1
) y
ON y.id = x.id;
The subquery in this query
SELECT id, name, keyt
FROM table
WHERE id = (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND() LIMIT 1)
would return only one record as it has LIMIT 1 added at the end.
Also, in your question, the table contains only 1 record for which
value of keyt = 21, due to which you're getting only one record.
If you want more records, you should remove the LIMIT. In that case you may rephrase your query as:
SELECT id, name, keyt
FROM table
WHERE id IN (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND())
Hope this is what you expected. As your actual goal is not very clear from the question.
Your table has two 21 in the keyt column so your subquery in the where clause returns 2 values if id that is 1 and 2.So what you need to do is instead of using an equal to operator "=" use IN operator in the where clause.
SELECT id, name, keyt FROM table WHERE id IN (SELECT t2.id FROM table t2 WHERE t2.keyt=21 ORDER BY RAND())

Why is this two table into one table union, where showing invalid result in MySQL?

I have a table1 (records 3), and table2 (records 3).
Where i have field name in both.
Now i want to make a result from those two table
which will show me both table records and take only one if there is duplicate.
from that result i will do main query using like or or other logical statements
So my expected output records will contain 5 rows not 6 rows. How do i do that?
Example:
table1: table2:
+-------------------------+ +--------------------------------+
| Name | ID | Name | ID
+-------------------------- +---------------------------------
| A | 1 | 1 December Name | 4
| B | 2 | D | 5
| 1 December Name | 3 | E | 6
My Expected output is following which works, but does not work when i use WHERE
like to only get '1 December Name':
+-----------------------------------------------------+
| Name | ID
+-----------------------------------------------------
| A | 1 table1
| B | 2 table1
| 1 December Name | 3 table2 or table1 (no unique)
| D | 4 table2
| E | 5 table2
I tried this:
SELECT * FROM
(
(
SELECT name AS name FROM table1
)
UNION
(
SELECT anothername AS name FROM table2
)
) as t
WHERE name like '%1 December Name%'
limit 1,10
Output: Your SQL query has been executed successfully ( Query took 0.2798 sec )
Problem: The following query has no error but it does not find that record which contain '1 December Name'
Follow up: works i know now which ID it used
SELECT NAME, ID, STATUS FROM
(
(
SELECT NAME AS name , id, CONCAT('table1') AS STATUS FROM table1
)
UNION ALL
(
SELECT ANOTHERNAME AS name, id, CONCAT( 'table2' ) AS STATUS FROM table2
)
) AS t
WHERE
t.NAME LIKE '%1 December Name%'
LIMIT 1 , 10;
You can get something similar to what you want:
select name, group_concat(id) from
(select name, 'table1' as id from table1
union all
select name, 'table2' from table2) x
group by name
Output would be:
+------------------------------------+
| Name | ID
--------------------------------------
| A | table1
| B | table1
| 1 December Name | table1,table2
| D | table2
| E | table2
UNION ALL is the right choice (not UNION), because it does not remove duplicates, and preserves row order
Try this
(SELECT name FROM table1 )
UNION (SELECT name FROM table2);