How to get rows even if count is 0? Only 1 table - mysql

I want the count even if the count is 0. My current query is
SELECT `id`,count(0) as `fetchpc` FROM `user` WHERE pid in('4,6,7,8') GROUP BY `id`
But it returns only those id where count is greater than 0
Edit:
the values used for in('4,6,7,8') are first fetched from database in another query. And then using a script rows are converted to 4,6,7,8.
So all the values are present in the database.
Also it is possible that the values returned can go upto 100+ values.

You could left join this query on a "fictive" query that queries these IDs as literals:
SELECT ids.id, COALESCE(cnt, 0)
FROM (SELECT 4 AS id
UNION ALL
SELECT 6 AS id
UNION ALL
SELECT 7 AS id
UNION ALL
SELECT 8 AS id) ids
LEFT JOIN (SELECT id, COUNT(*) AS cnt
FROM fetchpc
GROUP BY id) t ON t.id = ids.id

You can use a derived table. I would recommend:
SELECT i.id, COUNT(u.id) as fetchpc
FROM (SELECT 4 as id UNION ALL
SELECT 6 as id UNION ALL
SELECT 7 as id UNION ALL
SELECT 8 as id
) i LEFT JOIN
`user` u
ON u.id = i.id
GROUP BY i.id;
From a performance perspective, this is much better than aggregating first (in a subquery) and then joining. Basically, the aggregation (in that case) has to aggregate all the data and afterwards filter out the unnecessary rows.
This formulation filters the rows first, which should speed the aggregation.

Related

return the same record more than once in a query result

The following query:
SELECT * FROM table WHERE id IN (1,2,3);
will return three records.
SELECT * FROM table WHERE id IN (1,2,1);
will return just two records (for Ids 1 and 2)
Is there a way for the result set to contain two records for Id 1 (and three in total)?
You could try creating a table for the ids you want to filter by. This would get you your desired results. I'm not sure if mysql supports CTE, but hopefully this is enough for you to get the idea.
WITH IDS
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 1 AS id
)
SELECT T.*
FROM T
JOIN IDS
ON T.id = IDS.id

SQL query with repeated values in list

How to write a query correctly to get data without uniqueness?
I have list of ids, where ids are repeated.
Example: (1,1,1,2,3)
select *
from table
where id in (1,1,1,2,3);
returns only (1,2,3).
But I need to get with repeated entries.
Use a derived table and left join:
select t.*
from (select 1 as id union all select 1 union all select 1 union all select 2 union all select 3
) i left join
t
on t.id = i.id
The syntax for the derived table might vary depending on the database, but most support the above syntax.
That's not what WHERE statement is for, as it's only for filtering matching keys.
If you need to do that in this order, use sth like
select table.*
from (
select 1 as id
union select 1
union select 1
union select 2
union select 3
) myStaticKeys
join table using (id)

MYSQL count number of times value is in 3 columns

I have a query that gets some data about customers. This customers can have three phone numbers and these can be repeated.
To count the number of times that these phones are repeated a partner have create a subselect:
(select count(*)
from TABLE_A as k
where (k.phone=a.phone or k.phone2=a.phone or k.phone3=a.phone)
and k.id!=a.id) as repetitionsPhone1
This is inside a bigger select like this:
SELECT a.*,c.*,b.*,
(
select count(*)
from TABLE_A as k
where (k.phone=a.phone or k.phone2=a.phone or k.phone3=a.phone)
and k.id!=a.id
) as repetitionsPhone1
FROM a
left join c on a.id=c.id
left join b on a.id=b.id
This query takes for 50 rows about 30 seconds, and it should return about 2000 rows every single day.
To optimize this I use explain and I see that this subquery was the problem so I searched and I tried this:
SELECT phn,sum(count) as phoneRepetitions
from (
select k.phone1 as phn, count(*) as count
from k
group by k.phone1
UNION
select k.phone2 as phn,count(*) as count
from k
group by k.phone2
UNION
select k.phone3 as phn,count(*) as count
from k
group by k.phone3
) as aux
group by phn
And this returns #1062 MYSQL error: Duplicate entry for key 'distinct key'
First of all I would like to solve this problem. Anyone knows what is happening? This error seems logic in an insert statement, but in select?
And later, this will help to improve the big select that I must optimize? I will have to do this for the three columns.
Thank you.
SELECT count(*) from
(SELECT phones1 FROM k
union
SELECT phones2 from k
union
SELECT phones3 from k)
AS SumCountPhones
This seemed to work for me.
Solution as per How do I add two count(*) results together on two different tables?
You can keep stacking the unions.
SELECT
COUNT(*) AS CountOf FROM
table1
INNER JOIN
table2
GROUP BY phone1 , phone2 , phone3
HAVING COUNT(*) > 1

SQL: selecting the set of A not B

I have Two tables: left one is users_projects, right one is projects:
I want to select the projects that user 3 is not participating in (only p_ID 5 and 7).
I've tried SELECT * FROM users_projects up INNER JOIN projects p ON p.p_ID=up.p_ID WHERE up.u_ID!=3
but that also returns me p_ID 1 which both user 2 and 3 are a part of.
Thanks for your help!
A solution with LEFT JOIN:
SELECT
*
FROM
projects p LEFT JOIN users_projects up ON (p.p_ID = up.p_ID AND up.u_ID = 3)
WHERE
up.u_ID IS NULL
Basically select all Projects and join them with the user_projects of the desired user. Left join makes all rows from the project table appear even if the is no corresponding row in the users_projects table. These rows have all fields from the users_projects set to NULL, so we can just select those.
This is not a JOIN query, but a query with a non-correlated sub-select with a NOT IN() predicate.
I hope the columns of the projects table are enough ...
SELECT
*
FROM
( SELECT 1,'Apple' -- input data, don't use in 'real' query
UNION ALL SELECT 5,'Banna' -- input data, don't use in 'real' query
UNION ALL SELECT 7,'Carrot' -- input data, don't use in 'real' query
UNION ALL SELECT 8,'Durian') -- input data, don't use in 'real' query
projects(p_id,p_name)
WHERE p_id NOT IN (
SELECT
p_id
FROM
( SELECT 2,1 -- input data, don't use in 'real' query
UNION ALL SELECT 2,5 -- input data, don't use in 'real' query
UNION ALL SELECT 2,7 -- input data, don't use in 'real' query
UNION ALL SELECT 3,1 -- input data, don't use in 'real' query
UNION ALL SELECT 3,8) -- input data, don't use in 'real' query
users_projects(u_id,p_id)
WHERE u_id=3
)
;
p_id|p_name
7|Carrot
5|Banna

Finding item and dependent set of items from the same mysql table in one query

I have a table where I store items and the time where they are relevant. For this question the following columns are relevant:
CREATE TABLE my_items
(
id INTEGER,
category INTEGER,
t DOUBLE
);
I want to select all items from a specific category (e.g. 1) and the sets of items that have a time within +- 5 (seconds) from these items.
I will probably do this with two types of queries in a script:
SELECT id,t from my_items where category=1;
then loop over the result set, using each result row's time as t_q1, and do a separate query:
SELECT id from my_items where t >= t_q1-5 AND t <= t_q1+5;
How can I do this in one query?
You can use a join. Take your subquery that selects all category 1 items, and join it with the original table on the condition that the time is within +/- five. It's possible that duplicate rows are returned, so you can group by id to avoid that:
SELECT t.*
FROM myTable t
JOIN (SELECT id, timeCol FROM myTable WHERE category = 1) t1
ON t.timeCol BETWEEN (t1.timeCol - 5) AND (t1.timeCol + 5)
OR t.id = t1.id
GROUP BY t.id;
I added the OR t.id = t1.id to make sure that the rows of category 1 are still included.
You can use a single query with all you criteria if there is only one table
SELECT id,t from my_items where category=1 AND t >= t_q1-5 AND t <= t_q1+5;
If there is two tables, use a right join on the timestamps table for performance.
select id
from my_items i,
(select min(t) min_t, max(t) max_t from my_items where category=1) i2
where i.category = 1 or
i.t between i2.min_t-5 and i2.max_t+5