Simplification mysql query by subquery for finding pair in one table - mysql

I have following table in mysql:
id | pairType
1 | 2
2 | 2
3 | 1
4 | 1
I need get second value to pair by id. I`am able doing this by 2 separated mysql queries, but it would be more comfortable to have it in one.
For example:
first query:
SELECT `pairType`
FROM `tmp`
WHERE `id` = 1
//return 2
second query:
SELECT `id`
FROM `tmp`
WHERE `id` != 1 AND `pairType` = 2
Thank's a lot

Something like this should work:
SELECT id
FROM tmp
WHERE pairtype = (SELECT pairtype FROM tmp WHERE id = 1)
AND id <> 1

That is absolutely unclear what are you asking for.
But here are some random guesses:
http://sqlfiddle.com/#!9/ee0096/4
SELECT t.id
FROM tmp t
INNER JOIN tmp t_
ON t_.pairtype = t.id
t_.id = 1 ;
SELECT t.id
FROM tmp t
INNER JOIN tmp t_
ON t_.pairtype = t.pairtype
AND t_.id = 1
WHERE t.id != 1

Related

get the total count but exclude certain condition

Hello I had this table:
id | user_id | status
1 | 34 | x
2 | 35 | x
3 | 42 | x
4 | 42 | y
My goal is to count the data with X status except if the user has a another data with Y status, it will exclude in the count. So instead of 3, it will only count 2 since the 3rd row has another data which is the 4th row with y status.
SELECT * FROM logs
AND user_id NOT IN (SELECT user_id FROM logs WHERE status = 'y')
GROUP BY user_id;
We can try the following aggregation approach:
SELECT COUNT(*) AS cnt
FROM
(
SELECT user_id
FROM logs
GROUP BY user_id
HAVING MIN(status) = MAX(status) AND
MIN(status) = 'x'
) t;
The above logic only counts a user having one or more records only having x status.
You can do it this way, I only modify a bit on your sql
SELECT COUNT(*) FROM (
SELECT u_id FROM tbl WHERE u_id NOT IN
(SELECT u_id FROM tbl WHERE status = 'y')
GROUP BY u_id
) as t
You can use inner join:
SELECT
count(t1.id) AS `cnt`
FROM
`test` AS t1,
`test` AS t2
WHERE
t2.`status`='y'
&& t1.`user_id` != t2.`user_id`;

How can I select a row within a group based on a condition in SQL?

Question
Please consider the following table:
+--------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+--------------+--------+--------+
| 1 | A | I |
| 1 | A | J |
| 2 | B | B |
| 2 | B | K |
+--------------+--------+--------+
For each transactionID (2 rows are associated with ID 1, two rows with ID 2) I want to select the row for which Sgroup = Rgroup, if any row within a transactionID satisfies the condition. Otherwise, I want to select a row at random. For each transactionID at most one row satisfies Sgroup = Rgroup. How can I do this?
Attempted Solution
I know how to select rows for which the condition Sgroup = Rgroup is fulfilled as follows:
SELECT *
FROM Transaction
WHERE Sgroup = Rgroup;
+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
| 2 | B | B |
+---------------+--------+--------+
I also know how to chose a row randomly (thanks to this question) if the condition is not fulfilled as follows:
SELECT * FROM
(SELECT *
FROM Transaction
WHERE NOT transactionID IN
(SELECT transactionID
FROM Transaction
WHERE Sgroup = Rgroup)
ORDER BY RAND()) AS temp
GROUP BY temp.transactionID;
+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
| 1 | A | I |
+---------------+--------+--------+
How can I combine these two expressions into one? I tried working with a CASE expression I didn't get far. Can somebody kindly suggest a solution?
Example Code Here is the code to generate the table:
CREATE DATABASE MinimalExample;
USE MinimalExample;
CREATE TABLE Transaction (
transactionID int,
Sgroup nvarchar(1),
Rgroup nvarchar(1)
);
INSERT INTO Transaction VALUES
(1,'A','I'),
(1,'A','J'),
(2,'B','B'),
(2,'B','K');
I think variables might be the simplest solution if you really mean "random":
select t.*
from (select t.*,
(#rn := if(#i = transactionID, #rn + 1,
if(#i := transactionID, 1, 1)
)
) as rn
from (select t.*
from t
order by transactionID, (sgroup = rgroup) desc, rand()
) t cross join
(select #i := -1, #rn := 0) params
) t
where rn = 1;
If by "random" you mean "arbitrary", you can use this quick-and-dirty trick:
(select t.*
from t
where sgroup = rgroup
)
union all
(select t.*
from t
where not exists (select 1 from t t2 where t2.id = t.id and t2.sgroup = t2.rgroup)
group by transactionID
);
This uses the dreaded select * with group by, something which I strongly discourage using under almost all circumstances. However, in this case, you are specifically trying to reduce each group to an indeterminate row, so it doesn't seem quite so bad. I will note that MySQL does not guarantee that the columns in the result set all come from the same row, although in practice they do.
Finally, if you had a unique primary key on each row, you could use probably the simplest solution:
select t.*
from t
where t.id = (select t2.id
from t t2
where t2.transactionID = t.transactionID
order by (rgroup = sgroup) desc, rand()
);

MySQL - Select results with specified ID or with null

I have one table:
| ID | ADV_ID | USER_ID |
| 1 | 22 | NULL |
| 2 | 22 | 3 |
| 5 | 44 | NULL |
and now, I want to select row where adv_id = 22 and user_id = 3. If that row doesn't exist, I want to get row where adv_id = 22 and user_id is null.
I tried in that way:
SELECT * FROM `table` WHERE adv_id = 22 AND (user_id = 3 OR user_id is null)
but this query return two rows - with user_id = NULL and with user_id = 3. I want to get one row - with user_id = 3 or (if not exist), with user_id = NULL.
How I can do it in one query?
Thanks.
Use conditional aggregation:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT
ADV_ID,
CASE WHEN COUNT(CASE WHEN USER_ID = 3 THEN 1 END) > 0 THEN 3 END USER_ID
FROM yourTable
) t2
ON t1.ADV_ID = t2.ADV_ID AND
((t1.USER_ID IS NULL AND t2.USER_ID IS NULL) OR (t1.USER_ID = t2.USER_ID))
WHERE
t1.ADV_ID = 22;
Demo
For an explanation, the subquery I have aliased as t2 aggregates over the ADV_ID, and outputs the value 3 if that value occurs in one or more records, otherwise it outputs NULL. Then, we join this subquery back to your original table on the condition that both USER_ID values are NULL, or, if not, that the two USER_ID values match.
You may modify the demo to see that it generates the output you want for other inputs.
SELECT *
FROM test
WHERE ADV_ID IS NOT NULL AND USER_ID IS NOT NULL
UNION ALL
SELECT *
FROM test
WHERE USER_ID IS NULL AND NOT EXISTS (
SELECT 1
FROM test
WHERE ADV_ID IS NOT NULL AND USER_ID IS NOT NULL
)
Select all rows with the first condition: ADV_ID IS NOT NULL AND USER_ID IS NOT NULL
and then UNION ALL with the same table if the first condition is NOT EXISTS.
So we only get results if the first condition is not returned any rows.
The MySQL UNION ALL operator is used to combine the result sets of 2 or more SELECT statements.
try like that:
SELECT * FROM `table` t1 WHERE (t1.adv_id = 44)
AND ((t1.user_id = 3) OR
(NOT EXISTS (select * from `table` t2 where t2.adv_id=t1.adv_id and t2.user_id = 3) AND t1.user_id is null ))
DEMO

Limit result of join query and order

i have this query
select a.*,
GROUP_CONCAT(b.`filename`) as `filesnames`
from `school_classes` a
join classes_data.`classes_albums` b on a.`school_key` = b.`school_key`
and a.`class_key` = b.`class_key`
group by a.`ID`
the result of this query is
i want to add to it
ORDER BY b.added_date DESC LIMIT 2
so the output of filenames column only shows latest 2 files , ?
It is not clear from your question what your tables look like and how they relate but this might be what you are after.
drop table if exists school_classes;
create table school_classes (id int,school_key int, class_key int);
drop table if exists classes_albums;
create table classes_albums(id int,school_key int, class_key int, filename varchar(3),dateadded date);
insert into school_classes values
(1,1,1), (2,1,2),(3,1,3)
insert into classes_albums values
(1,1,1,'a','2017-01-01'),(1,1,1,'b','2017-02-01'),(1,1,1,'c','2017-03-01');
select a.*, b.filenames
from school_classes a
join
(
select c.school_key,c.class_key,group_concat(c.filename order by c.rn desc) filenames
from
(
select c.*,
if(concat(c.school_key,c.class_key) <> #p, #rn:=1, #rn:=#rn+1) rn,
#p:=concat(c.school_key,c.class_key) p
from classes_albums c, (select #rn:=0, #ck:=0,#sk:=0) rn
order by c.school_key,c.class_key, c.dateadded desc
) c
where c.rn < 3
group by c.school_key,c.class_key
) b on b.school_key = a.school_key and b.class_key = a.class_key
+------+------------+-----------+-----------+
| id | school_key | class_key | filenames |
+------+------------+-----------+-----------+
| 1 | 1 | 1 | b,c |
+------+------------+-----------+-----------+
1 row in set (0.02 sec)

PHP single query Multiple UPDATE effecting AUTO_INCREMENT id instead of order_id

Here is my super-simple table layout...
id | order
1 | 1
2 | 2
I've been trying to update the order for both entries with a single query however my query tests seem to keep updating the auto_increment id field.
My goal is to make id1 = order 2 and id2 = order1 in a single query. What am I doing wrong with my query?
UPDATE forms
SET order = CASE id
WHEN 1 THEN 2
WHEN 2 THEN 1
END
WHERE id IN (1,2);
How about doing JOIN?
UPDATE Tablename AS a
INNER JOIN Tablename AS b
ON a.id = 1 AND b.id = 2
SET a.order = b.order,
b.order = a.order
SQLFiddle Demo