How to set 0 when the count row display Null? - mysql

So, I have this sql:
SELECT program.BilanganTerhad - IFNULL(COUNT(daftarprogram.KodProgram), 0) AS kiraan
FROM program, daftarprogram
WHERE program.KodProgram = daftarprogram.KodProgram
AND daftarprogram.KodProgram = '19'
How can I set the null COUNT() value to 0? For example: 10 - null = null instead of 10 - 0 = 10.
I need the count become 0, not null.
This is value from table1
While this is value from table2
I want to subtract value from table1 and minus with count(kodprogram)
The thing is I want to subtract value from table1 with count(KodProgram) from table2 based on where condition = KodProgram

COUNT() never returns NULL. That said, your query is malformed (in addition to using archaic join syntax. BilanganTerhad is in the SELECT but it is an aggregation query.
Perhaps you intend:
SELECT p.BilanganTerhad - COUNT(*) AS kiraan
FROM program p JOIN
daftarprogram dp
ON p.KodProgram = dp.KodProgram
WHERE dp.KodProgram = '19'
GROUP BY p.BilanganTerhad;

Related

Get columns with value 0 on `group by` with `count`

I'm using this query to get the count of rows grouped by cmp2 field but I need to get a column for every cmp2 even if its sum result is 0. I can't get it this way:
SELECT CMP2, COALESCE(count(*), 0) as count
FROM datos_con851_0,
datos_con851_1
WHERE datos_con851_0.REGISTRO = datos_con851_1.REGISTRO
AND SPEEDER = 1
GROUP BY CMP2;
You want a left join, presumably something like this:
SELECT d0.CMP2, count(d1.REGISTRO) as count
FROM datos_con851_0 d0 left join
datos_con851_1 d1
on d0.REGISTRO = d1.REGISTRO AND
d1.SPEEDER = 1 -- just guess this comes from `d1`
GROUP BY d0.CMP2;

How efficiently check record exist more than 2 times in table using sub-query?

I have a query like this . I have compound index for CC.key1,CC.key2.
I am executing this in a big database
Select * from CC where
( (
(select count(*) from Service s
where CC.key1=s.sr2 and CC.key2=s.sr1) > 2
AND
CC.key3='new'
)
OR
(
(select count(*) from Service s
where CC.key1=s.sr2 and CC.key2=s.sr1) <= 2
)
)
limit 10000;
I tried to make it as inner join , but its getting slower . How can i optimize this query ?
The trick here is being able to articulate a query for the problem:
SELECT *
FROM CC t1
INNER JOIN
(
SELECT cc.key1, cc.key2
FROM CC cc
LEFT JOIN Service s
ON cc.key1 = s.sr2 AND
cc.key2 = s.sr1
GROUP BY cc.key1, cc.key2
HAVING COUNT(*) <= 2 OR
SUM(CASE WHEN cc.key = 'new' THEN 1 ELSE 0 END) > 2
) t2
ON t1.key1 = t2.key1 AND
t1.key2 = t2.key2
Explanation:
Your original two subqueries would only add to the count if a given record in CC, with a given key1 and key2 value, matched to a corresponding record in the Service table. The strategy behind my inner query is to use GROUP BY to count the number of times that this happens, and use this instead of your subqueries. The first count condition is your bottom subquery, and the second one is the top.
The inner query finds all key1, key2 pairs in CC corresponding to records which should be retained. And recognize that these two columns are the only criteria in your original query for determining whether a record from CC gets retained. Then, this inner query can be inner joined to CC again to get your final result set.
In terms of performance, even this answer could leave something to be desired, but it should be better than a massive correlated subquery, which is what you had.
Basically get the Columns that must not have a duplicate then join them together. Example:
select *
FROM Table_X A
WHERE exists (SELECT 1
FROM Table_X B
WHERE 1=1
and a.SHOULD_BE_UNIQUE = b.SHOULD_BE_UNIQUE
and a.SHOULD_BE_UNIQUE2 = b.SHOULD_BE_UNIQUE2
/* excluded because these columns are null or can be Duplicated*/
--and a.GENERIC_COLUMN = b.GENERIC_COLUMN
--and a.GENERIC_COLUMN2 = b.GENERIC_COLUMN2
--and a.NULL_COLUMN = b.NULL_COLUMN
--and a.NULL_COLUMN2 = b.NULL_COLUMN2
and b.rowid > a.ROWID);
Where SHOULD_BE_UNIQUE and SHOULD_BE_UNIQUE2 are columns that shouldn't be repeated and have unique columns and the GENERIC_COLUMN and NULL_COLUMNS can be ignored so just leave them out of the query.
Been using this approach when we have issues in Duplicate Records.
With the limited information you've given us, this could be a rewrite using 'simplified' logic:
SEELCT *
FROM CC NATURAL JOIN
( SELECT key1, key2, COUNT(*) AS tally
FROM Service
GROUP
BY key1, key2 ) AS t
WHERE key3 = 'new' OR tally <= 2;
Not sure whether it will perform better but might give you some ideas of what to try next?

MySQL return 'empty result' even with coalesce

I have some trouble with MySQL.
Here is the query I use:
SELECT
COALESCE(SUM(`a`.`battles`), 0) AS `battles`
FROM
`account_stats` AS `a`
WHERE
`a`.`account_id` = 12345
GROUP BY
`a`.`account_id`
The Table account_stats is not empty, but has no row with account_id = 12345.
I want that MySQL returns 0 battles instead of Empty set. But even with COALSECE or IFNULL it returns Empty set.
When I remove the GROUP BY everything works fine, but I need it to calculate the SUM of battles.
Is there a way to workaround this problem?
If you only want information on one account, you can use conditional aggregation if you want the query to return a row with the value of 0:
SELECT SUM(CASE WHEN a.account_id = 12345 THEN a.battles ELSE 0 END) as battles
FROM account_stats a;
If the table is not empty, then you don't need coalesce().
If you have an index on account_id and the table is big, the following would probably be more efficient because the subquery would use the index and the rest of the query would be manipulating a single row:
SELECT x.account_id, COALESCE(SUM(a.battles), 0) as battles
FROM (SELECT 12345 as account_id
) x LEFT JOIN
(SELECT a.account_id, SUM(a.battles) as battles
FROM account_stats a
WHERE a.account_id = 12345
) a
ON x.account_id = a.account_id;

Set default value with "IN" statment?

How to set default value with "IN" statment, like this:
SELECT username
FROM user
WHERE id IN (1,2,3,4)
ORDER BY FIELD(id,1,2,3,4)
If id = 2 is not available then return 0 or null, like this:
John33
0
amanda1
erik
You need to do this with a left join:
SELECT u.username
FROM (select 1 as id union all select 2 union all select 3 union all select 4
) ids left join
user u
on u.id = ids.id
ORDER BY FIELD(id, 1, 2, 3, 4);
Logic in the where clause cannot "add" new rows to the result set.
An IN (list) comparison returns a boolean, (TRUE, FALSE or NULL) for every row it's evaluated for.
So, a foo IN (list) cannot (by itself) "produce" a row that's not available in the row source.
(You say that id = 2 "is not available", we take that to mean that there is no row in user that satisfies that predicate.)
You could produce the resultset as shown, but it doesn't require an IN comparison at all.
You need a rowsource that is guaranteed to return the "id" values you want; an inline view is a convenient way to do that.
SELECT u.username
FROM ( SELECT 1 AS id
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
) n
LEFT
JOIN user u
ON u.id = n.id
ORDER BY n.id
The LEFT JOIN specifies an outer join operation. That is, if there is no matching row from the table on the right side (user) that matches a row from the table on the left side (n), then the query will return the row from n along with NULL values for all the columns from user.
You can replace that NULL value for username replaced using an expression in the SELECT list. Check if u.id is NULL (which would mean there was no matching row found), and return something else. For example, the literal 0.
SELECT IF(u.id IS NULL,'0',u.username) AS username
That's MySQL specific syntax for the ANSI-standard equivalent
SELECT CASE WHEN u.id IS NULL THEN '0' ELSE u.username END AS username
If you want to replace all NULL values of username, not just NULL values produced when a user row is missing:
SELECT IFNULL(u.username,'0') AS username

Getting this query to work?

Heya!, I have the below query:
SELECT t1.pm_id
FROM fb_user_pms AS t1,
fb_user_pm_replies AS t2
WHERE (t1.pm_id = '{$pm_id}'
AND t1.profile_author = '{$username}'
OR t1.pm_author = '{$username}'
AND t1.pm_id = t2.pm_id
AND t2.pm_author = '{$username}'
AND COUNT(t2.reply_id) > 0)
AND t1.deleted = 0
However, I'm getting a grouping error - my guess is its caused by the AND COUNT(t2.reply_id) > 0?
How can I rectify the above query to make it work.
Hope someone can help.
Cheers!
The aggregate function COUNT can't go in the WHERE clause. You should use a GROUP BY and put it in the HAVING clause.
SELECT t1.pm_id
FROM fb_user_pms AS t1
JOIN fb_user_pm_replies AS t2 ON t1.pm_id = t2.pm_id
WHERE (
(t1.pm_id = '{$pm_id}' AND t1.profile_author = '{$username}') OR
(t1.pm_author = '{$username}' AND t2.pm_author = '{$username}')
) AND t1.deleted = 0
GROUP BY t1.pm_id
HAVING COUNT(t2.reply_id) > 0
If t2.reply_id is a NOT NULL column then you don't need the HAVING clause at all.
The error is because you can't use an aggregate function (COUNT, MIN, MAX, AVG, etc) in the WHERE clause, without it being inside a subquery. Only the HAVING clause allows you to use aggregates without being wrapped in subqueries.
But checking for replies to be more than zero is not necessary on an INNER JOIN - that guarantees that there will be at least one reply associated to the fb_user_pms record. The JOIN also means that the information in t1 will be duplicated for every supported record in fb_user_pm_replies. IE: If a fb_user_pms record has three fb_user_pm_replies records related to it, you'll see the fb_user_pms record in the result set three times.
The query you want to use is:
SELECT t1.pm_id
FROM fb_user_pms AS t1
WHERE t1.pm_id = '{$pm_id}'
AND '{$username}' IN (t1.profile_author, t1.pm_author)
AND t1.deleted = 0
AND EXISTS(SELECT NULL
FROM fb_user_pm_replies AS t2
WHERE t2.pm_id = t1.pm_id
AND t2.pm_author = '{$username}')
The EXISTS clause returns true or false, based on the WHERE criteria. It also won't duplicate t1 results.
The condition with COUNT must be in the HAVING part. It can not be part of the WHERE part.
The SELECT part must be also use aggregate functions for example MAX(t1.pm_id)