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
Related
I have this query.
SELECT * FROM Customer WHERE TAGID IN ('UK', 'Germany');
This outputs the results to show all customers in UK and Germany, but as you can imagine, there will be loads of outputs, and I just require it to output 2 results for UK and 2 results for Germany?
Is this possible?
UNION ALL comes to mind:
(SELECT c.*
FROM Customer c
WHERE TAGID = 'UK'
LIMIT 2
) UNION ALL
(SELECT c.*
FROM Customer c
WHERE TAGID = 'Germany'
LIMIT 2
);
Note that this can take advantage of an index onCustomer(TagID). Also, this returns two arbitrary rows. You can use an ORDER BY to return the newest, oldest, biggest, smallest, reddest, bluest or whatever.
Here is a db<>fiddle.
Yes It is possible. Please check below methods.
Method 1 :
SELECT TOP 2 * FROM Customer WHERE TAGID ='UK'
UNION ALL
SELECT TOP 2 * FROM Customer WHERE TAGID = 'Germany'
Method 2:
(SELECT * FROM Customer WHERE TAGID ='UK' LIMIT 2)
UNION ALL
(SELECT * FROM Customer WHERE TAGID = 'Germany' LIMIT 2)
Method 3:
(SELECT * FROM Customer WHERE TAGID ='UK' AND ROWNUM = 2)
UNION ALL
(SELECT * FROM Customer WHERE TAGID = 'Germany' AND ROWNUM = 2)
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.
I have a database table "tblfavs" with five columns: id, userid, logoid, favdate, did.
I want to determine the percentage of a user's (userid) favorites (id) that share the same designer id (did), and where userid <> did, displayed from highest percentage to lowest.
In pseudo-query format:
SELECT [percentage], userid, did
FROM tblfavs
WHERE record has the same userid and did
AND userid <> did
GROUP BY userid
ORDER BY [percentage] DESC
I can't get my head around the query to accomplish this. Help appreciated!
Edit:
Sample data
1, 1, 5, 2017-01-01, 2
2, 7, 3, 2017-01-02, 5
3, 1, 8, 2017-01-02, 2
4, 7, 1, 2017-01-02, 3
In this set user 1 (second column) has two entries and both have "2" as the designer id (final column).
Expected output
100%, userid 1, did 2
50%, userid 7, did 5
50%, userid 7, did 3
etc.
This is easier in other DBMS which feature window functions (e.g. COUNT OVER). However, this is not that difficult in MySQL either. You just need two aggregations: Count per userid and did, count per userid, divide.
select
ud.cnt * 100.0 / u.cnt as percentage,
ud.userid,
ud.did
from
(
select userid, did, count(*) as cnt
from tblfavs
group by userid, did
) ud
join
(
select userid, count(*) as cnt
from tblfavs
group by userid
) u on u.userid = ud.userid
order by percentage desc;
Try this (improved from the previous answer to match your exact input-so you get % for each row not agregated)
select
ud.cnt2 * 100.0 / u.cnt as percentage,
ud.userid,
ud.did
from
(
select
out3.userid,out3.did, cnt2
from
(select userid,did from tblfavs) out3
join
(
select
userid, did, count(*) as cnt2
from tblfavs
group by userid, did
) ud on ud.userid = out3.userid and ud.did = out3.did
) ud
join
(
select userid, count(*) as cnt
from tblfavs
group by userid
) u on u.userid = ud.userid
order by percentage desc;
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.
I have the following data inside a table:
id person_id item_id price
1 1 1 10
2 1 1 20
3 1 3 50
Now what I want to do is group by the item ID, select the id that has the highest value and take the price.
E.g. the sum would be: (20 + 50) and ignore the 10.
I am using the following:
SELECT SUM(`price`)
FROM
(SELECT id, person_id, item_id, price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
ORDER BY id DESC) x
GROUP BY item_id
However, this query is still adding (10 + 20 + 50), which is obviously not what I need to have.
Any ideas to where I am going wrong?
Here is what you are trying to achieve. First you need grouping in a subquery and not in outer query. In outer query you need only sum:
SELECT SUM(`price`)
FROM
(SELECT MAX(price) as price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
GROUP BY item_id) x
http://sqlfiddle.com/#!9/40803/5
SELECT SUM(t1.price)
FROM tbl t1
LEFT JOIN tbl t2
ON t1.person_id= t2.person_id
AND t1.item_id = t2.item_id
AND t1.id<t2.id
WHERE t1.person_id = 1
AND t2.id IS NULL;
I'm not sure if this is the only requirement you have. If so, try this.
SELECT SUM(price)
FROM
(SELECT MAX(price)
FROM table
WHERE person_id = 1
GROUP BY item_id)
First of all - you don't need the person table, because the other table already contains the person_id. So i removed it from the examples.
Your query returns a sum of prices for each item.
If you replace SELECT SUM(price) with SELECT item_id, SUM(price) you wil get
item_id SUM(`price`)
1 30
3 50
But that is not what you want. Neither is it what you wrote in the question " (10 + 20 + 50)".
Now replacing the first line with SELECT id, item_id, SUM(price) you will get one row for each item with the highest id.
id item_id price
2 1 20
3 3 50
This works because of the "undocumented feature" of MySQL, wich allows you to select columns that are not listed in the GROUP BY clause and get the first row from the subselect each group (each item in this case).
Now you only need to sum the price column in an additional outer select
SELECT SUM(price)
FROM (
SELECT id, item_id ,price
FROM (
SELECT id, person_id, item_id, price
FROM `table` tbl
WHERE tbl.person_id = 1
ORDER BY id DESC ) x
GROUP BY item_id
) y
However i do not recomend to use that "feature". While it still works on MySQL 5.6, you never know if that will work with newer versions. It already doesn't work on MariaDB.
Instead you can determite the MAX(id) for each item in an subselect, select only the rows with the determined ids and get the summed price of them.
SELECT SUM(`price`)
FROM `table` tbl
WHERE tbl.id IN (
SELECT MAX(tbl2.id)
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
)
Another solution (wich internaly does the same) is
SELECT SUM(`price`)
FROM `table` tbl
JOIN (
SELECT MAX(tbl2.id) as id
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
) x ON x.id = tbl.id
Alex's solution also works fine, if the groups (number of rows per person and item) are rather small.
You have used group by in main query, but it is on subquery like
SELECT id, person_id, item_id, SUM(`price`) FROM ( SELECT MAX(price) FROM `table` tbl WHERE p.person_id = 1 GROUP BY item_id ) AS x