Sequelize Subtraction of counts - mysql

I am trying to get the count by subtracting all records that have false from all the records that have true. I am unable to replicate such a thing in Sequelize but I was able to create it in a raw query:
SELECT (SELECT Count(id)
FROM votes
WHERE up = true
AND id = 1) - (SELECT Count(id)
FROM votes
WHERE up = false
AND id = 1) AS votes
Based off the documentation, I do not see a way to do such a thing. Is there anything that I am missing?

This may be simpler for your js lib to handle
select count(case when up = true then 1 end) - count(case when up = false then 1 end)
from votes
where id = 1
then this previous answer should help I think:
https://stackoverflow.com/a/47397320/2067753
Note that the count() function ignores nulls, but using sum() instead of count can give the same end result:
select sum(case when up = true then 1 else 0 end) - sum(case when up = false then 1 else 0 end)
from votes
where id = 1
using group by:
select id, count(case when up = true then 1 end) - count(case when up = false then 1 end)
from votes
where id = 1
group by id

Related

Filtering MySQL output without referencing alias but where SUM(CASE) is used

With a view to remediating missing userIDs in our database, I'm trying to look at instances where - within the same table, the same user is found with and without IDs. So far, I have a rough result using the following:
SELECT users,
SUM(CASE WHEN UserID = "" THEN 1 ELSE 0 END) as InstancesWithoutIDs,
SUM(CASE WHEN UserID <> "" THEN 1 ELSE 0 END) as InstancesWithIDs,
COUNT(*) as TOTAL
FROM table.users
GROUP BY name;
I would now like a where InstancesWithIDs > 0 filter applied to the table. But as I keep reading, I can't reference an alias in the filter. From googling around, I think the best I've gotten is:
SELECT * from (
SELECT users,
SUM(CASE WHEN UserID = "" THEN 1 ELSE 0 END) as InstancesWithoutIDs,
SUM(CASE WHEN UserID <> "" THEN 1 ELSE 0 END) as InstancesWithIDs,
COUNT(*) as TOTAL
FROM table.users) A
where InstancesWithIDs > 0;
But this then displays all results as a single record.
users || InstancesWithoutIDs || InstancesWithIDs
A. Fisher 62588 947711
How can I get the full table displayed, as I did with the top query?
Any help much appreciated!!
You can use Having (only when you use GROUP BY) like this:
SELECT users,
SUM(CASE WHEN UserID = "" THEN 1 ELSE 0 END) as InstancesWithoutIDs,
SUM(CASE WHEN UserID <> "" THEN 1 ELSE 0 END) as InstancesWithIDs,
COUNT(*) as TOTAL
FROM table.users
GROUP BY name
HAVING InstancesWithIDs > 0;
HAVING would be the equivalent to WHERE but for aggregated functions

How to minimize sql query

I have a booking table in MySQL database where I need to get 3 data.
1) Total Booking
2) Pending Booking ( where is_confirm = 1 )
3) Complete Booking ( where is_confirm = 0 )
Now, I am writing 3 separate query to get this but how can I get it using 1 query?
current query:
$booking = new Admin;
$booking->rowQuery("SELECT count(bid) AS totalBooking FROM booking");
$bookingData = $booking->result->fetch_assoc();
$totalBooking = $bookingData['totalBooking'];
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 1 ");
$completeBooking = $booking->rows;
$booking->rowQuery("SELECT bid FROM booking WHERE is_confirm = 0 ");
$pendingBooking = $booking->rows;
you can use case sql . Try this:
SELECT
COUNT(CASE WHEN is_confirm = 1 THEN 1 END) AS confirmCount,
COUNT(CASE WHEN is_confirm = 0 THEN 1 END) AS noconfirmCount,
COUNT(*) AS total
FROM booking;
SELECT count(bid) AS totalBooking FROM booking
UNION
SELECT bid FROM booking
WHERE is_confirm=1
UNION
SELECT bid FROM booking
WHERE is_confirm=0
Aggregate functions usually skip nulls, including group_concat. If you don't mind explodeing the result string later, you could use case expressions to get the total bookings and coma-delimited strings for the IDs:
SELECT COUNT(bid) AS totalBooking,
GROUP_CONCAT(CASE is_confirm WHEN 1 THEN bid END) AS pendingBookings,
GROUP_CONCAT(CASE is_confirm WHEN 0 THEN bid END) AS completeBookings
FROM booking

SQL Vertical grouping

I have the following RDB Table:
ID Feature
1 1
1 2
2 1
3 1
3 2
3 3
What I want is the following output:
ID Feature1 Feature2 Feature3
1 true true false
2 true false false
3 true true true
What's the simplest SQL query to achieve this?
Get all the id's with all feature combinations using a cross join and left join the original table on to this to get the required result.
select i.id,
max(case when f.feature=1 and t.feature is not null then 'true' else 'false' end) as feature1,
max(case when f.feature=2 and t.feature is not null then 'true' else 'false' end) as feature2,
max(case when f.feature=3 and t.feature is not null then 'true' else 'false' end) as feature3
from (select distinct feature from t) f --replace this with the feature table if you have one
cross join (select distinct id from t) i
left join t on t.id=i.id and t.feature=f.feature
group by i.id
If you just need boolean values 1,0 for True,False the query can be simplified to
select i.id,
max(f.feature=1 and t.feature is not null) as feature1,
max(f.feature=2 and t.feature is not null) as feature2,
max(f.feature=3 and t.feature is not null) as feature3
from (select distinct feature from t) f --replace this with the feature table if you have one
cross join (select distinct id from t) i
left join t on t.id=i.id and t.feature=f.feature
group by i.id
I believe all you would need is a simple pivot query. Here, I used boolean values to flag whether or not a feature exists (1 for true, 0 for false).
SELECT f.ID
, Feature1 = SUM(CASE WHEN f.Feature = 1 THEN 1 ELSE 0 END)
, Feature2 = SUM(CASE WHEN f.Feature = 2 THEN 1 ELSE 0 END)
, Feature2 = SUM(CASE WHEN f.Feature = 3 THEN 1 ELSE 0 END)
FROM dbo.Features (NOLOCK) f
GROUP BY f.ID
You just need conditional aggregation:
select id, max(feature = 1) as feature1, max(feature = 2) as feature2,
max(feature = 3) as feature3
from t
group by id;
The above returns 0 and 1. If you actually want the strings true and false, you can do:
select id,
(case when max(feature = 1) then 'true' else 'false' end) as feature1,
(case when max(feature = 2) then 'true' else 'false' end) as feature2,
(case when max(feature = 3) then 'true' else 'false' end) as feature3
from t
group by id;

Get both results with one query

I want to get results for likes by a specific user-id and all likes and dislikes of a specific page id.
My structure looks like this:
`pages`: (id, title)
`pages_likes`: (id, page_id, uid, status)
If the status is -1 it's a dislike of a specific page, if it's 1 it's a like.
So, to get all likes this is my query:
SELECT COUNT(id) FROM pages_likes WHERE status = '1'
But now I also want to get if user-id 3 for example likes this page with
SELECT COUNT(id) FROM pages_likes WHERE status = '1' AND uid='3'
How can I achieve both in one query? I guess there has to be changed something right after the SELECT statement?
If you want to do this in a single query, use conditional aggregation:
SELECT SUM(CASE WHEN uid = '3' THEN 1 ELSE 0 END) AS threeLikes,
SUM(CASE WHEN uid <> '3' THEN 1 ELSE 0 END) AS otherLikes
FROM pages_likes
WHERE status = '1'
Another option would be to use a UNION, cf. the answer given by #bernie
Update:
If you want page likes and dislikes in the same query, you can try:
SELECT SUM(CASE WHEN uid = '3' AND status = '1' THEN 1 ELSE 0 END) AS threeLikes,
SUM(CASE WHEN uid <> '3' AND status = '1' THEN 1 ELSE 0 END) AS otherLikes
SUM(CASE WHEN uid = '3' AND status = '0' THEN 1 ELSE 0 END) AS threeDislikes,
SUM(CASE WHEN uid <> '3' AND status = '0' THEN 1 ELSE 0 END) AS otherDisikes
FROM pages_likes
I think this would work:
SELECT '' user, COUNT(id) likes
FROM pages_likes
WHERE status = '1'
GROUP BY 1
UNION ALL
SELECT uid user, COUNT(id) likes
FROM pages_likes
WHERE status = '1' AND uid='3'
GROUP BY 1
I would do it this way:
SELECT COUNT(*) AS total_likes, SUM(uid=3) AS uid3_likes
FROM pages_likes
WHERE status=1 AND page_id=1234
Re your comment:
Here's an example of showing total likes, and total dislikes. It's similar to the answer from #TimBiegeleisen.
SELECT SUM(status=1) AS total_likes,
SUM(CASE WHEN uid=3 AND status=1 THEN 1 END) AS uid3_likes
SUM(CASE WHEN uid=3 AND status=-1 THEN 1 END) AS uid3_dislikes
FROM pages_likes
WHERE page_id=1234

SQL using CASE in count and group by

I'm using CASE to categorize data in the table and count them but the results aren't accurate
live demo [here]
select DATE(date) as day, count(*),
count(distinct case when name = 'fruit' then 1 else 0 end) as fruits,
count(distinct case when name = 'vege' then 1 else 0 end) as vege,
count(distinct case when name = 'sweets' then 1 else 0 end) as sweets
from food
group by day
with rollup
I'm not sure if the issue is with CASE or in the string matching = because there's no 'sweets' still it counts 1?
any pointers I'd be grateful
Your problem is that COUNT counts every result that is not NULL. In your case you are using:
COUNT(distinct case when name = 'sweets' then 1 else 0 end)
So, when the name is not sweets, it counts the 0. Furthermore, since you are using DISTINCT, it counts just one or two values. You should either use SUM or remove the DISTINCT and the ELSE 0:
SELECT DATE(date) as day,
COUNT(*),
SUM(CASE WHEN name = 'fruit' THEN 1 ELSE 0 END) as fruits,
SUM(CASE WHEN name = 'vege' THEN 1 ELSE 0 END) as vege,
SUM(CASE WHEN name = 'sweets' THEN 1 ELSE 0 END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Or:
SELECT DATE(date) as day,
COUNT(*),
COUNT(CASE WHEN name = 'fruit' THEN 1 ELSE NULL END) as fruits,
COUNT(CASE WHEN name = 'vege' THEN 1 ELSE NULL END) as vege,
COUNT(CASE WHEN name = 'sweets' THEN 1 ELSE NULL END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Here is a modified sqlfiddle.
You can't group by an alias. You have to group by the expression.
group by date(date)
You can group on an Alias:
SELECT
FROM_UNIXTIME(UnixTimeField, '%Y') AS 'Year'
,FROM_UNIXTIME(UnixTimeField, '%m') AS 'Month'
FROM table p
GROUP BY Year, Month