Calculate count records from mysql group by fields - mysql

My table in MySQL
http://joxi.ru/5mdWRV8tyQzyr1
My programm pass array users
$ids = [1, 3, 7];
My query for table:
SELECT responsible_id, count(id) as count
from test
WHERE active = 1
AND status = 3
AND responsible_id in (1, 3, 7)
GROUP BY responsible_id
ORDER BY count(id)
I get result http://joxi.ru/vAWYGq0IMxdjmW
But, I need also first row with responsible_id = 7 and count = 0 if not exist on table.

To do what you want, use a left join:
SELECT v.responsible_id, count(t.id) as count
FROM (SELECT 1 as responsible_id UNION ALL
SELECT 3 as responsible_id UNION ALL
SELECT 7 as responsible_id
) v LEFT JOIN
test t
ON t.responsible_id = v.responsible_id AND
t.active = 1 AND
t.status = 3
GROUP BY v.responsible_id
ORDER BY count(id);
Note that the conditions in the WHERE have been moved to the ON clause.

Related

Random elements inside JOIN

I have this code here
INSERT INTO Directory.CatalogTaxonomy (`CatalogId`, `TaxonomyId`, `TaxonomyTypeId`, `IsApprovalRelevant`)
SELECT cat.CatalogId, dep.Id, #department_type, false
FROM Directory.Catalog cat
JOIN (SELECT * FROM (
SELECT * FROM Taxonomy.Department LIMIT 10
) as dep_tmp ORDER BY RAND() LIMIT 3) AS dep
WHERE cat.CatalogId NOT IN (SELECT CatalogId FROM Directory.CatalogTaxonomy WHERE TaxonomyTypeId = #department_type)
AND cat.UrlStatus = #url_status_green
AND (cat.StatusId = #status_published
OR cat.StatusId = #status_review_required);
And the problem is that, it should for each catalog take the first 10 elements from Department and randomly choose 3 of them, then add to CatalogDepartment 3 rows, each containing the catalog id and a taxonomy id. But instead it randomly chooses 3 Department elements and then adds those 3 elements to each catalog.
The current result looks like this:
1 000de9d7-af8b-4bac-bdbd-e6e361e5bc5e
1 001d4060-2924-4c75-b304-d780454f261b
1 001bc4b8-c1bc-498d-9aee-3825a40587d5
2 000de9d7-af8b-4bac-bdbd-e6e361e5bc5e
2 001d4060-2924-4c75-b304-d780454f261b
2 001bc4b8-c1bc-498d-9aee-3825a40587d5
3 000de9d7-af8b-4bac-bdbd-e6e361e5bc5e
3 001d4060-2924-4c75-b304-d780454f261b
3 001bc4b8-c1bc-498d-9aee-3825a40587d5
As you can see, there are only 3 departments chosen and repeated for every catalog
If you think that the query:
SELECT * FROM (
SELECT * FROM Taxonomy.Department LIMIT 10
) as dep_tmp
ORDER BY RAND() LIMIT 3
that you join to Directory.Catalog returns 3 different departments for each catalog then you are wrong.
This query is executed only once and returns 3 random departments which are joined (always the same 3) to Directory.Catalog.
What you can do is after you CROSS JOIN 10 departments to Directory.Catalog, choose randomly 3 of them for each catalog.
Try this:
INSERT INTO Directory.CatalogTaxonomy (`CatalogId`, `TaxonomyId`, `TaxonomyTypeId`, `IsApprovalRelevant`)
WITH cte AS (
SELECT cat.CatalogId, dep.Id AS TaxonomyId, #department_type AS TaxonomyTypeId, false AS IsApprovalRelevant
FROM Directory.Catalog AS cat
CROSS JOIN (SELECT * FROM Taxonomy.Department LIMIT 10) AS dep
WHERE cat.CatalogId NOT IN (SELECT CatalogId FROM Directory.CatalogTaxonomy WHERE TaxonomyTypeId = department_type)
AND cat.UrlStatus = #url_status_green
AND (cat.StatusId = #status_published OR cat.StatusId = #status_review_required);
)
SELECT t.CatalogId, t.TaxonomyId, t.TaxonomyTypeId, t.IsApprovalRelevant
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CatalogId ORDER BY RAND()) rn
FROM cte
) t
WHERE t.rn <= 3
Note that this:
SELECT * FROM Taxonomy.Department LIMIT 10
does not guarantee that you get the first 10 elements from Department because a table is not ordered.

Return WHERE IN clause rows even if table doesn't contain the given row

mytable contains records for id 1, 2, 3, 10, 12 and 20, and specifically does not include records for id 5 and 15.
How can I perform some query such as:
SELECT id, id IN (1,5,10,15,20) AS status
FROM mytable
WHERE id IN (1,5,10,15,20);
and return records:
id status
1 true
5 false
10 true
15 false
20 true
If there was some other table, I could just outer join mytable, but there is none. The following will certainly not work, but is there some sort of fictional table I can join against?
SELECT id, isnull(mytable.id) AS status
FROM *
LEFT OUTER JOIN mytable
WHERE id IN (1,5,10,15,20);
You can create a derived table in the FROM clause:
SELECT i.id, (t.id is not null) AS status
FROM (SELECT 1 as id UNION ALL SELECT 5 UNION ALL SELECT 10 UNION ALL SELECT 15 UNION ALL SELECT 20
) i LEFT JOIN
mytable t
ON i.id = t.id;

How to i order values depending on its numbers of hits

I want to retrieve the table value in order of from most to least. For example, if we had a single column table like the following,
selected_val
2
3
3
2
1
3
1
1
1
4
I need a SQL that will return the values in the order of 1, 3, 2, 4, because there are four 1's, three 3's, two 2's, and one 4 in the table. I want 1,1,1,1,3,3,3,2,2,4. Is this possible?
ANd if i add more colums that
selected_val Rack
2 A
3 A
3 B
2 B
1 C
3 C
1 A
1 A
1 B
4 C
Thanks for the help
you can use count and group by
select selected_val
from my_table
group by selected_val
order by count(*) DESC
for the secondo part of the question you can use group concat if you need the rack related to selected_vale
select selected_val, group_concat(rack)
from my_table
group by selected_val
order by count(*) DESC
or add the column rack to group by if you need the relative counting and order
select selected_val, rack
from my_table
group by selected_val, rack
order by count(*) DESC
TRY THIS for the desired output and you can select other columns as well:
select t.selected_val
from test t
inner join (
select t1.selected_val, count(1) ord
from test t1
group by t1.selected_val) t2 on t2.selected_val = t.selected_val
order by t2.ord desc
OUTPUT:
1
1
1
1
3
3
3
2
2
4
Output is not actually in row but you can use GROUP_CONCAT to retrieve output in a row.
Use subquery to count, then LEFT JOIN result to the subquery's result and order by count.
select t1.selected_val from table t1
left join (
SELECT
t2.selected_val,
count(*) AS count
FROM table t2
GROUP BY selected_val
) t3 on t1.selected_val = t3.selected_val
ORDER BY t3.count DESC;
Using Cross Join.
select A.C,A.Rack from
(select selected_val,Rack,count(*) c from #TableName group by selected_val,Rack)a
,(select selected_val,Rack,count(*) c from #TableName group by selected_val,Rack)b
where B.c <= A.selected_val
ORDER BY A.selected_val DESC
OutPut :

Fill in missing rows with zeros

I am trying to get ratings, for a particular item in my database. Not all items have a rating for 1, 2, 3, 4 or 5; when that happens, how can I fill in the row with 0's?
So, for example when I have ratings for 1,2,3 but not for 4 and 5, how could I fill in those two rows with 0's?
select
rating,
count(rating) as rating_count,
(count(rating) / (select count(item_id) from ratings where item_id = 3) * 100) as percent,
avg(rating)
from ratings
where item_id = 3
group by rating desc
with rollup
Here is the above result for the above query, as you can see there is no 1 and 2 rating, how can I get those where rating_count, percent and avg(rating) are zeros?
#Hogan's answer:
This is what I have got working (based on #Hogan's original query):
select
r_list.r as rating,
ifnull(count(rating), 0) as rating_count,
ifnull((count(rating) / (select count(item_id) from ratings where item_id = ?) * 100), 0) as percent,
ifnull(avg(rating), 0)
from (SELECT 1 AS r
UNION ALL
SELECT 2 AS r
UNION ALL
SELECT 3 AS r
UNION ALL
SELECT 4 AS r
UNION ALL
SELECT 5 AS r
) r_list
left join ratings on r_list.r = ratings.rating and item_id = ?
group by r_list.r desc
with rollup
You will use someting along the lines of this to replace the null values as a 0:
SELECT ISNULL(rating, 0 ) FROM myTable

How to write a SQL query?

My database has a simple table, with two columns, BID and Value. There may be some records in the database with same BID, like this:
BID Value
Record1: BID = 1, Value = 0
Record2: BID = 1, Value = 3
Record3: BID = 2, Value = 4
Record4: BID = 2, Value = 5
Record5: BID = 2, Value = 6
Record6: BID = 3, Value = 7
Now I want to write a SQL query that can get the total count of the BID that has more than one corresponding records.
In the above sample, BID 1 has 2 corresponding records, and BID 2 has 3. So the total count of BID values that has more than one corresponding records is 2.
How to write such a SQL query?
You are looking for an aggregation query.
SELECT COUNT(*)
FROM (
SELECT BID, COUNT(*) cnt
FROM your_table
GROUP BY BID
HAVING COUNT(*) > 1
) q
The inner query here groups your bids together, counts how many in each group, and then selects only those groups with more than 1 value.
The outer query simply counts the results of that query.
You can see how it works here: http://sqlfiddle.com/#!9/0c9e6/3
declare #t table (bid int,val int)
insert into #t (bid,val)values (1,0),(1,3),(2,4),(2,5),(2,6),(3,7)
;with cte as (
select bid,
val,ROW_NUMBER()OVER(PARTITION BY bid order by val )RN from #t
)
select COUNT( DISTINCT bid) from cte
where RN > 1
you need only 2 count one for checking the count of values for each id and the other for all ids who has more than one value, you don't need to use having:
SELECT COUNT(*)
FROM (
SELECT BID, COUNT(*) CNT
FROM your_table
GROUP BY BID
) q
WHERE CNT>1