SELECT with a COUNT of another SELECT - mysql

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.

Related

sql query to select records from 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)

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

why the sql correct and the inner mechanism for run it?

the sql as follows come from mysql document. it is:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
The document say It finds all rows in table t1 containing a value that occurs twice in a given column , and doesnot explain the sql.
t1 and t is the same table, so the
count(*) in subquery == select count(*) from t
, isn't it?
count(*) in subquery == select count(*) from t
is wrong. because in mysql you can't use it like that. so you have to run it like that to get result of same id having two rows.
if you want to get count of same occurrence,
SELECT id, name, count(*) AS all_count FROM t1 GROUP BY id HAVING all_count > 1 ORDER BY all_count DESC
And also you can get values as your query like this as well,
select * from t1 where id in ( select id from t1 group by id having count(*) > 1 )
The query contains a correlated subquery in WHERE clause:
SELECT COUNT(*) FROM t1 WHERE t1.id = t.id
It is called correlated because it is related to the main query via t.id. So, this subquery counts the number of records having an id value that is equal to the current id value of the record returned by the main query.
Thus, predicate
(SELECT COUNT(*) FROM t1 WHERE t1.id = t.id) = 2
evaluates to true for any row with an id value that occurs twice in the table.
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
This query goes through each record in t1 and then in the subquery looks into t1 again to see if in this case id is found 2 times (and only 2 times). You can do the same for any other column in t1 (or any table for that matter).
When you would like to see all values that are multiple times in the table, change WHERE 2 = by WHERE 1 <. This will also give you the values that are 3 times, 4 times, etc. in the table.
{
SELECT id,count( * )
FROM
MyTable
group by id
having count( * )>1
}
with this code, you can see the rows which repet more than one,
and you can change this query by yourself
How about using GROUP BY and HAVING:
SELECT id, count(1) as Total FROM MyTable AS t1
GROUP BY t1.id
HAVING Total = 2

Select something from mysql database and order it by count (where)

I have a problem with selecting something from my database. Here is the sql sentence:
SELECT name
FROM table1
JOIN table2
ON table1.id=table2.advid
GROUP BY advid
ORDER BY COUNT(table2.likes) ASC
This will output name with the least table2.likes to the highest value of table2.likes
The problem is that table2.likes contain both likes and dislikes. Likes are marked with 1, and dislikes are marked with 2 in the table.
Currently, if there is...
...written in the table, the syntax will count both likes and dislikes so the result would be 6. I would need this result to be zero, which means when counting, dislikes have to be deduced from the number of likes. Which also means this part of the sentence: ORDER BY COUNT(table2.likes) ASC would have to be changed, but I don't know how.
Use conditional aggregation with SUM():
SELECT name
FROM table1 t1 JOIN
table2 t2
ON t2.id = t2.advid
GROUP BY name
ORDER BY SUM(CASE WHEN t2.likes = 1 THEN 1 ELSE -1 END) ASC;
Note: I changed the GROUP BY to be by name. The GROUP BY columns should match the columns you are selecting.
Use a case expression to count 1 for likes and -1 for dislikes. It is considered good style and less error-prone not to join and then aggregate, but to join the already aggregated data instead.
select t1.name, t2.sumlikes
from table1 t1
join
(
select advid, sum(case when likes = 1 then 1 else -1 end) as sumlikes
from table2
group by advid
) t2 on t2.advid = t1.id
order by sumlikes;
If you want to list names without like entries, too, then turn the join into a left outer join and select coalesce(t2.sumlikes, 0) instead.

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.