Mysql IF statement return issues - mysql

I have this query where the IF lines are only partially returning correct result:
SELECT
COALESCE((SELECT COUNT(ID) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS ADDED,
COALESCE((SELECT SUM(CASE WHEN USERS_BUCKETS.STATUS='Completed' THEN 1 ELSE 0 END) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS DONE,
COALESCE((SELECT COUNT(ID) FROM USERS_LIKES WHERE USERS_LIKES.USERID = USERS.ID),0) AS NUM_LIKES,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.USER_ID=USERS.ID),0) AS FOLLOWING,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.FOLLOW_ID=USERS.ID),0) AS FOLLOWERS,
(SELECT IF(ADDED >= 5,1,0)) AS IFADDED,
(SELECT IF(DONE >= 3,1,0)) AS IFDONE,
(SELECT IF(NUM_LIKES >= 5,1,0)) AS IFNUM_LIKES,
(SELECT IF(FOLLOWING >= 5,1,0)) AS IFFOLLOWING,
(SELECT IF(FOLLOWERS >= 3,1,0)) AS IFFOLLOWERS,
(SELECT IF(ADDED >= 5,1,0) + IF(DONE >= 3,1,0) + IF(NUM_LIKES >= 5,1,0) + IF(FOLLOWING >= 5,1,0) + IF(FOLLOWERS >= 3,1,0)) AS PROGRESS
FROM USERS
WHERE USERS.ID=?
Result:
ADDED: 20
IFADDED: 1
DONE: 9
IFDONE: 0 //should be 1
NUM_LIKES: 11
IFNUM_LIKES: 1
FOLLOWING: 11
IFFOLLOWING: 0 //should be 1
FOLLOWERS: 10
IFFOLLOWERS: 0 //should be 1
PROGRESS: 2
What's wrong? All IF values should be 1 and PROGRESS should be 5.
Note: I am using PDO in php, but I don't think that matters at all.

I have no idea why your code is working. The columns are definitely not the column aliases defined earlier in the query.
To do what you want, use a subquery and simplify the logic:
SELECT u.*, (ADDED >= 5) AS IFADDED,
(DONE >= 3) AS IFDONE,
(NUM_LIKES >= 5) AS IFNUM_LIKES,
(FOLLOWING >= 5) AS IFFOLLOWING,
(FOLLOWERS >= 3) AS IFFOLLOWERS,
((ADDED >= 5) + (DONE >= 3) + (NUM_LIKES >= 5) + (FOLLOWING >= 5) +
(FOLLOWERS >= 3)
) AS PROGRESS
FROM (SELECT COALESCE((SELECT COUNT(ID) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS ADDED,
COALESCE((SELECT SUM(CASE WHEN USERS_BUCKETS.STATUS='Completed' THEN 1 ELSE 0 END) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID = USERS.ID),0) AS DONE,
COALESCE((SELECT COUNT(ID) FROM USERS_LIKES WHERE USERS_LIKES.USERID = USERS.ID),0) AS NUM_LIKES,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.USER_ID=USERS.ID),0) AS FOLLOWING,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.FOLLOW_ID=USERS.ID),0) AS FOLLOWERS
FROM USERS
WHERE USERS.ID = ?
) u;
This takes advantage of the fact that MySQL treats booleans as integers in a numeric context, with "1" for true and "0" for false.
EDIT: I should also note that the coalesce() is unnecessary because count() will return 0 when there are no matches.

Related

SQLSERVER Running Balance

Actually i have problem on my query to get the running balance , i have debit and credit transaction i need one column to showing the cumulative running balance this is the code i used :
Select * From (
Select D.AccNo, H.[Date], A.AccountName, H.TrxNo,
(Case When ((D.Remark = '') or (D.Remark is Null)) Then H.Trxnote Else D.Remark End) As TrxDetailDescA,
(D.Debit * 1) AS DebitValue, (D.Credit * 1) AS CreditValue,SUM(COALESCE(D.Debit, 0) - COALESCE(D.Credit, 0)) AS Balance
From TblHeadTrans H, TblTransDetails D, TblAccount A
Where H.Guid = D.[LineNo]
And D.AccNo = A.AccountNo
And H.[Date] >= '01-01-2022' And H.[Date] <= '10-07-2022' And D.AccNo >= '1003'
group by AccNo,H.[Date],A.AccountName,H.TrxNo,D.Remark,h.Trxnote,d.Debit,d.Credit
Union All
Select D.AccNo, Null As TrxDate, A.AccountName, Null As TrxNo,
'Opening Balance' As TrxDetailDesc,
Case When (Sum(D.Debit * 1) - Sum(D.Credit *1)) < 0 then 0
Else (Sum(D.Debit * 1) - Sum(D.Credit * 1)) End As DebitValue,
Case When (Sum(D.Credit * 1) - Sum(D.Debit * 1)) < 0 then 0
Else (Sum(D.Credit * 1) - Sum(D.Debit * 1)) End As CreditValue
, SUM(COALESCE(d.Debit, 0) - COALESCE(d.credit, 0)) AS Balance
From TblHeadTrans H, TblTransDetails D, TblAccount A
Where H.guid = D.[LineNo] And D.AccNo = A.AccountNo
And d.[Date] < '01-01-2022' And D.accno = '1003'
Group By D.AccNo, A.AccountName,H.Date,H.TrxNo
) ReportData
WHERE 1=1
Order By AccNo, [Date], TrxNo
and the result showing as the picture:
the result

Limit to two results for each individual ID

How would I return two results for each individual meeting.id?
I've tried things like Row_Count() and Rank() but they seem to cause syntax errors.
This is my query which I need adapting to show the two results per meeting.id.
SELECT meeting_appointment.* FROM `meeting`
INNER JOIN meeting_appointment ON (
meeting_appointment.meeting_id = meeting.id AND meeting_appointment.pupil_id = 0 AND meeting_appointment.guardian_id = 0 AND meeting_appointment.deleted = 0
)
WHERE (
meeting.grade_id = "-1" OR meeting.grade_id IN ('87')
)
AND meeting.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR AND meeting.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
GROUP by meeting_appointment.id
ORDER BY meeting_appointment.startTime ASC
If your meeting_appointment.id are consecutive then this should show the first two
meeting_appointment.id per meeting.id:
SELECT meeting_appointment.* FROM `meeting`
INNER JOIN meeting_appointment ON (meeting_appointment.meeting_id = meeting.id)
WHERE (meeting.grade_id = "-1" OR meeting.grade_id IN ('87'))
AND meeting.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR AND meeting.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
AND meeting_appointment.pupil_id = 0
AND meeting_appointment.guardian_id = 0
AND meeting_appointment.deleted = 0
AND NOT EXISTS
(SELECT 1 FROM meeting_appointment ma WHERE ma.id<meeting_appointment.id-1
AND ma.pupil_id = 0
AND ma.guardian_id = 0
AND ma.deleted = 0
)
GROUP by meeting_appointment.id
ORDER BY meeting_appointment.startTime ASC
If you meeting_appointment.id are just random or non-numeric then it might need some tweaks but in order to code those teaks we'll need to know a bit more about the schema.
You don't have an aggregate function, so GROUP BY is redundant. Remove that, and add a LIMIT clause, and you should be good to go:
SELECT ma.*
FROM meeting m
INNER JOIN meeting_appointment ma ON ma.meeting_id = m.id
WHERE m.grade_id IN ('-1','87')
AND ma.pupil_id = 0
AND ma.guardian_id = 0
AND ma.deleted = 0
AND m.startTime < '2016-10-06 14:00:00' + INTERVAL 1 HOUR
AND m.startTime > '2016-10-06 14:00:00' - INTERVAL 1 HOUR
ORDER BY ma.startTime ASC
LIMIT 2;
You could also use BETWEEN for the datetime column.

how to get SUM() of COUNT() column in MySQL

i have the following query, tried using case statement
SELECT t.inst_id, t.inst_username, tcm.city_name,
SUM(CASE WHEN psb.pms_student_bucket_id IS NULL THEN 1 ELSE 0 END) AS not_assiged,
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) BETWEEN 1 AND 50 THEN 1 ELSE 0 END) AS '1-50',
SUM(CASE WHEN COUNT(psb.pms_student_bucket_id) > 50 THEN 1 ELSE 0 END) AS ' > 50'
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id;
I need SUM of pms_student_bucket_id column when their COUNT is '1-50' and '>50'. Right now this query is saying Invalid use of group function.
How would I SUM on COUNT of "pms_student_bucket_id" equals/between some value in mysql?
you could put it in a subquery
SELECT inst_id, inst_username, city_name,
SUM(pms_student_bucket_id IS NULL ) AS not_assiged,
SUM(num_bucket >=10 AND num_bucket <= 20) AS '10 - 20'
SUM(num_bucket <= 50) AS '1-50',
SUM(num_bucket > 50) AS ' > 50'
FROM
( SELECT t.inst_id, t.inst_username, tcm.city_name,psb.pms_student_bucket_id,
COUNT(psb.pms_student_bucket_id) as num_bucket
FROM tbl_si_di t
JOIN tbl_city_master tcm ON tcm.city_id = t.city_ref_id
JOIN tbl_si_students tss ON tss.inst_ref_id = t.inst_id
LEFT JOIN pms_student_bucket psb ON psb.user_ref_id = tss.user_ref_id
GROUP BY t.inst_id
)t1
GROUP BY inst_id;
note you can use the boolean values returned to do what you want.. aka you don't need a case statement, the boolean value returns a 1 or 0 which can then be summed..

SQL Server row_number and datatables

I'm working with SQL Server and Datatables in a PHP environment; I've researched a bit, and found that by using row_number I can achieve paged results, but I am getting:
The multi-part identifier "Flags.FlagValue" could not be bound.
SELECT dbo.PlayingCharacters.PlayerName,dbo.PlayingCharacters.CurrentLevel,dbo.PlayingCharacters.XP,(SELECT CASE WHEN dbo.PlayingCharacters.Karma >= 1 THEN 2 WHEN dbo.PlayingCharacters.Karma <= -1 THEN 1 ELSE 0 END) as Karma,ISNULL(Flags.FlagValue,0) AS Remort FROM ( SELECT row_number() OVER (ORDER BY dbo.PlayingCharacters.XP desc) AS CI_offset_row_number, dbo.PlayingCharacters.PlayerName, dbo.PlayingCharacters.CurrentLevel, dbo.PlayingCharacters.XP, (SELECT CASE WHEN dbo.PlayingCharacters.Karma >= 1 THEN 2 WHEN dbo.PlayingCharacters.Karma <= -1 THEN 1 ELSE 0 END) as Karma, ISNULL(Flags.FlagValue, 0) AS Remort FROM dbo.PlayingCharacters LEFT JOIN dbo.Flags ON dbo.Flags.OwnerID = dbo.PlayingCharacters.UserID AND Flags.FlagID = 30419 WHERE dbo.PlayingCharacters.AccountName NOT IN (SELECT DISTINCT AccountName FROM UserFlags WHERE FlagBitPosition BETWEEN 0 AND 40) AND PlayingCharacters.AccountName NOT LIKE 'DeletedFrom:%' ) AS A WHERE A.CI_offset_row_number BETWEEN (141) AND (150)
Upon examining the query, and a bit of further research I found that "AS A" near the end of the query may be the culprit.. But I am unsure. I am familiar with SQL to an extent, but with this it seems I am a fish out of water.. I cannot seem to figure out how to fix this query.
I apologize if this may have been asked prior, I found a few results regarding my error but couldn't put together any combination of answers with any success.
As a side note, this is my query before trying to add a limit/offset with row_number()
SELECT TOP 30 dbo.PlayingCharacters.PlayerName, dbo.PlayingCharacters.CurrentLevel, dbo.PlayingCharacters.XP, (SELECT CASE WHEN dbo.PlayingCharacters.Karma >= 1 THEN 2 WHEN dbo.PlayingCharacters.Karma <= -1 THEN 1 ELSE 0 END) as Karma, ISNULL(Flags.FlagValue, 0) AS Remort
FROM dbo.PlayingCharacters
LEFT JOIN dbo.Flags ON dbo.Flags.OwnerID = dbo.PlayingCharacters.UserID AND Flags.FlagID = 30419
WHERE dbo.PlayingCharacters.AccountName NOT IN (SELECT DISTINCT AccountName FROM UserFlags WHERE FlagBitPosition BETWEEN 0 AND 40) AND PlayingCharacters.AccountName NOT LIKE 'DeletedFrom:%'
ORDER BY dbo.PlayingCharacters.XP desc
Which works, but obviously doesn't perform the desired limit/offset. The code I am using to generate the query in question was grabbed from: http://codeigniter.com/forums/viewthread/160626/P10/#985759
try this one
SELECT temp.PlayerName,temp.CurrentLevel,temp.XP,
temp.Karma,temp.Remort FROM ( SELECT row_number() OVER (ORDER BY
dbo.PlayingCharacters.XP desc) AS CI_offset_row_number,
dbo.PlayingCharacters.PlayerName, dbo.PlayingCharacters.CurrentLevel,
dbo.PlayingCharacters.XP, (SELECT CASE WHEN
dbo.PlayingCharacters.Karma >= 1 THEN 2 WHEN
dbo.PlayingCharacters.Karma <= -1 THEN 1 ELSE 0 END) as Karma,
ISNULL(Flags.FlagValue, 0) AS Remort FROM dbo.PlayingCharacters
LEFT JOIN dbo.Flags ON dbo.Flags.OwnerID =
dbo.PlayingCharacters.UserID AND Flags.FlagID = 30419 WHERE
dbo.PlayingCharacters.AccountName NOT IN (SELECT DISTINCT AccountName
FROM UserFlags WHERE FlagBitPosition BETWEEN 0 AND 40) AND
PlayingCharacters.AccountName NOT LIKE 'DeletedFrom:%' ) temp WHERE
temp.CI_offset_row_number BETWEEN (141) AND (150)

selecting total comments (pos & neg) + latest comment for each

I am writing a query to get the top 10 rated businesses, the number of positive comments for each business, the number of negative comments for each business and the latest comment for each of these businesses.
SELECT comment.bis_id, Sum( Case When comment.rating <= 2 Then 1 Else 0 End ) As NegVotes
, Sum( Case When comment.rating >= 4 Then 1 Else 0 End ) As PosVotes, bis.bis_name
FROM bis, comment
WHERE comment.bis_id = bis.bis_id
GROUP BY bis_id
ORDER BY PosVotes DESC
LIMIT 0, 10";
The above gets positive comments and negative comments, but I can't seem to work out how to get the latest comment as well.
SELECT
c.bis_id
, Sum( Case When c.rating <= 2 Then 1 Else 0 End ) As NegVotes
, Sum( Case When c.rating >= 4 Then 1 Else 0 End ) As PosVotes
, b.bis_name
, cc.last_comment
FROM bis b
INNER JOIN comment c on (c.bis_id = b.bis_id)
INNER JOIN (SELECT c2.bis_id, c2.comment_text as last_comment
FROM comment c2
GROUP BY c2.bis_id
HAVING c2.comment_date = MAX(c2.comment_date) ) cc
ON (cc.bis_id = b.bis_id)
GROUP BY b.bis_id
ORDER BY PosVotes DESC
LIMIT 10 OFFSET 0