sql query to select records from mysql - mysql

Can suggest me the best way to select records from MySQL
customer
--------
id bed_id status
1 1 vocated
2 1 booked
3 2 vocated
bed
-----
id name
1 lower
2 middle
3 upper
I need to select bed which are vacated or not allotted
Here, the expected results are
The empty bed should be: bed_id's = 2 and 3
what is best SQL query to get this kind of result

Join the tables and group by the bed's id and put the conditions in a HAVING clause:
select b.id, b.name
from bed b left join customer c
on c.bed_id = b.id
group by b.id
having (
sum(status = 'vacated') > 0
and
sum(status = 'booked') = 0
) or sum(status is null) > 0
I'm not sure if you need and or or in the conditions

Try this-
SELECT * FROM bed
WHERE ID NOT IN (
SELECT DISTINCT bed_id FROM customer
WHERE Status = 'booked'
)
Note: This wll work for your current data. But if I think practical, you need to check the latest status of a BED in the customer table. That case you need to provide data with more variety and more explanation of your requirement.

You can apply a reverse logic by not exists :
select *
from bed b
where not exists
(
select bed_id
from customer
where status != 'vocated' and status = 'booked'
and bed_id = b.id);
Demo

You could find the most recent status using a correlated sub query and a left join to find rooms that have never had activity
select group_concat(s.t1id) availablerooms
from
(
select t1.id t1id,t1.name,t.id,t.bed_id,t.status
from t1
left join t on t1.id = t.bed_id
where t.id = (select max(id) from t where t1.id = t.bed_id) or
t.id is null
) s
where s.status <> 'booked' or s.status is null;
+----------------+
| availablerooms |
+----------------+
| 2,3 |
+----------------+
1 row in set (0.00 sec)

Related

skip row if user_id contains a specific code

I have these rows
user_id code
1 9103
1 9103
1 9001
2 9103
3 9103
3 9104
4 9103
4 9103
4 9001
I want to get only id that not contains 9001, then only 2 and 3
I try with Distinct But I without lucky
Select distinct v.code, user_id from mytable as v
where v.code not in ( Select v2.code from mytable as v2
where v2.code=9001)
Group by the user and then take only those groups having no record of the condition
select user_id
from your_table
group by user_id
having sum(code = 9001) = 0
There are multiple methods to get the results you need.
NOT EXISTS (ALL DBMS)
SELECT
*
FROM
Table1
WHERE
NOT EXISTS (
SELECT
1
FROM
Table1
WHERE
code = 9001
)
NOT IN (ALL DBMS)
SELECT
DISTINCT
Table1.user_id
FROM
Table1
WHERE
user_id NOT IN (
SELECT
user_id
FROM
Table1
WHERE
code = 9001
)
RIGHT JOIN / LEFT JOIN (ALL DBMS but for example SQLite does not support RIGHT JOIN)
SELECT
DISTINCT
Table1.user_id
FROM (
SELECT
user_id
FROM
Table1
WHERE
code = 9001
) AS Table1_filter
RIGHT JOIN
Table1
ON
Table1_filter.user_id = Table1.user_id
WHERE
Table1_filter.user_id IS NULL
;
SELECT
DISTINCT
Table1.user_id
FROM
Table1
LEFT JOIN (
SELECT
user_id
FROM
Table1
WHERE
code = 9001
) AS Table1_filter
ON
Table1_filter.user_id = Table1.user_id
WHERE
Table1_filter.user_id IS NULL
;
Conditional SUM (#juergen d answer) (ALL DBMS)
SELECT
Table1.user_id
FROM
Table1
GROUP BY
Table1.user_id
HAVING
SUM(Table1.code = 9001) = 0
Variation on (#juergen d answer) with GROUP_CONCAT (MySQL and SQLite only)
Also possible with
... HAVING FIND_IN_SET('9001', GROUP_CONCAT(Table1.code)) = 0 (MySQL Only)
SELECT
Table1.user_id
FROM
Table1
GROUP BY
Table1.user_id
HAVING
GROUP_CONCAT(Table1.code) NOT LIKE '%9001%'
p.s GROUP_CONCAT(Table1.code) NOT LIKE '%9001%' might also select false positives depending on the data used. Using FIND_IN_SET('9001', GROUP_CONCAT(Table1.code)) = 0 is more safe option to use.
see demo http://sqlfiddle.com/#!9/fc6f6b/34

mysql query that does not return an id with multiple entries

I wasn't sure how to word the title, but here is what I am trying to do. I have a table where the id can have multiple entries
id | number
___________
1 | 90
1 | 88
2 | 88
3 | 88
I want a query that will return all ids that don't contain the number 90, so only 2 and 3 in this example. I have tried the below, but it still returns the id of 1 since it also has a number of 88.
SELECT DISTINCT id FROM table WHERE number NOT IN (90)
One way of getting the result is by using NOT EXISTS. Basically what it does it it gets all ID which has 90 in the inner query and the NOT EXISTS only shows all ID not in the inner query.
SELECT A.*
FROM TableName a
WHERE NOT EXISTS (SELECT NULL
FROM TableName B
WHERE a.ID = b.ID
AND b.number = 90)
Here's a Demo.
An alternative is by using LEFT JOIN which yields the same result as above.
SELECT a.*
FROM TableName a
LEFT JOIN TableName b
ON a.ID = b.ID
AND b.number = 90
WHERE b.id IS NULL
Here's a Demo.
You can use subquery:
SELECT id
FROM table
WHERE id NOT IN (SELECT id FROM table WHERE number = 90)
You can use aggregation as illustrated below for better performance:
SELECT ID
FROM YourTable
GROUP BY ID
HAVING NOT INSTR(GROUP_CONCAT(`number`),'90');
Demo on SQL Fiddle.

Select all rows that have same ID

I have this table:
ID | Part
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | D
3 | E
4 | B
4 | D
and want a query that will grab all ID's that have an A, and return a list of all other parts with that ID.
e.g: Want Parts related to B:
Part | Count
A | 1
C | 2
D | 1
What I have currently:
SELECT * FROM tble WHERE ID IN (SELECT DISTINCT ID FROM tble t WHERE Part = ?)
GROUP BY Part ORDER BY COUNT(Part) DESC
This works, but is quite slow and I'm looking to improve it, but having difficulty
Your query is not unreasonable, although the distinct is unnecessary and I would use exists rather than in. And, the outer select needs to be fixed for the aggregation
SELECT t.part, COUNT(*)
FROM tble t
WHERE EXISTS (SELECT 1 FROM tble t2 WHERE t2.ID = t.ID AND t2.Part = ?)
GROUP BY t.Part
ORDER BY COUNT(*) DESC;
Then, to optimize this query, you want an index:
create index idx_tble_id_part on tble(id, part);
Simplify this.. Once you have the logic down, then add back in the SELECT * FROM..
SELECT Part, COUNT(Part) As Count_of_Part
GROUP BY Part ORDER BY COUNT(Part) DESC
Do a join from the table back to itself on ID, and then count the distinct values that pop up:
SELECT b.part, COUNT(DISTINCT b.id)
FROM
table as a
INNER JOIN table as b ON
a.id = b.id AND
a.part <> b.part
WHERE
a.part = 'B'
GROUP BY b.part
This can be simply done by joining back to the table:
SELECT t1.part
,count(*)
FROM tble t1
INNER JOIN tble t ON t.id = t1.id
AND t.part = 'B'
AND t1.part <> t.part
GROUP BY t1.part
SQL Fiddle Demo
You should be able to do this by grouping the data.
Try something like this:
SELECT part, COUNT(id) AS TotalCountId
FROM TABLE_NAME
GROUP BY ID

SELECT with a COUNT of another SELECT

I have a table in SQL that is a list of users checking in to a website. It looks much like this:
id | date | status
------------------
Status can be 0 for not checking in, 1 for checked in, 2 for covered, and 3 for absent.
I'm trying to build one single query that lists all rows with status = 0, but also has a COUNT on how many rows have status = 3 on each particular id.
Is this possible?
MySQL VERSION
just join a count that is joined by id.
SELECT t.*, COALESCE(t1.status_3_count, 0) as status_3_count
FROM yourtable t
LEFT JOIN
( SELECT id, SUM(status=3) as status_3_count
FROM yourtable
GROUP BY id
) t1 ON t1.id = t.id
WHERE t.status = 0
note: this is doing the boolean sum (aka count)..
the expression returns either true or false a 1 or a 0. so I sum those up to return the count of status = 3 for each id
SQL SERVER VERSION
SELECT id, SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) as status_3_count
FROM yourtable
GROUP BY id
or just use a WHERE status = 3 and a COUNT(id)
Try a dependent subquery:
SELECT t1.*,
( SELECT count(*)
FROM sometable t2
WHERE t2.id = t1.id
AND t2.status = 3
) As somecolumnname
FROM sometable t1
WHERE t1.status=0
You can use a join for this. Write one query that will get all rows with a status zero:
SELECT *
FROM myTable
WHERE status = 0;
Then, write a subquery to get counts for the status of 3 for each id, by grouping by id:
SELECT COUNT(*)
FROM myTable
WHERE status = 3
GROUP BY id;
Since you want all the rows from the first table (at least that's what I am picturing), you can use a LEFT JOIN with the second table like this:
SELECT m.id, m.status, IFNULL(t.numStatus3, 0)
FROM myTable m
LEFT JOIN (SELECT id, COUNT(*) AS numStatus3
FROM myTable
WHERE status = 3
GROUP BY id) t ON m.id = t.id
WHERE m.status = 0;
The above will only show the count for rows containing an id that has status 0. Hopefully this is what you are looking for. If it is not, please post some sample data and expected results and I will help you try to reach it. Here is an SQL Fiddle example.

Query to return rows according to column conditon

I am trying to write a query where given a table of users with a column name (for ex) "Likes", i want to select all those users that have records with both a 0 and a 1 for the "Likes" column. The schema looks something like this:
id Name Likes
0 Tom 1
1 Alice 0
2 Tom 0
The query should return rows with id = 0 and id = 2 since Tom has both a 1 and a 0 for the Like column. What is the simplest/most efficient query to accomplish this sort of behavior?
If Likes can be only 1 or 0 in your table and nothing else, you can do this.
select distinct t1.Name From tableName t1
join tableName t2 on t1.name = t2.name and t1.Likes = 1 - t2.Likes
If that is not the case, just do this:
select distinct t1.Name From tableName t1
join tableName t2 on t1.name = t2.name and t1.Likes = 1 and t2.Likes = 0
Another possible solution is this one.
select a.* from
tableName a
JOIN
(
select b.Name, count(distinct b.likes) as Likes
from tableName b
group by b.Name
having count(distinct b.likes) > 1
) a1 on a.Name = a1.Name
Assuming your table is called tab, you can use:
SELECT *
FROM tab a
WHERE (SELECT count(distinct b.likes)
FROM tab b
WHERE a.name = b.name
AND b.likes in(0, 1)
) = 2
This can easily be extended to any number of distinct likes that are required. Just enumerate them in the IN clause, and compare the subselect to the number of values.