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;
Related
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;
I want to return all the minimum dates of every single clients in the table and display it as "FIRST" if it is the MIN date, and IF its not, it will return "OTHER"
this is my query
SELECT TRANS_DATE, IF(TRANS_DATE= MIN(TRANS_DATE), 'FIRST', 'OTHER') AS TR_CODE
FROM `posthis`
WHERE datepost IS NOT NULL
My query only returns the MIN()
this is the result that I need
CLIENTID TRANS_DATE TR_CODE
02-00002234 2002-02-01 FIRST
02-00002234 2002-02-02 OTHER
02-00002234 2002-02-03 OTHER
02-00002235 2003-01-03 FIRST
02-00002235 2003-01-05 OTHER
02-00002235 2003-01-06 OTHER
02-00002236 2003-01-03 FIRST
02-00002236 2003-01-04 OTHER
02-00002236 2003-01-13 OTHER
Using MIN() as an analytic function would really come in handy for your problem. But since MySQL does not support this, we can use a join instead. In the query below, I LEFT JOIN the posthis table to a subquery which identifies the earliest date for each client. Should a record in posthis match to this subquery, we label it with a code 'FIRST', otherwise we label 'OTHER'.
SELECT
t1.CLIENTID,
t1.TRANS_DATE,
CASE WHEN t2.CLIENTID IS NOT NULL THEN 'FIRST' ELSE 'OTHER' END AS TR_CODE
FROM posthis t1
LEFT JOIN
(
SELECT CLIENTID, MIN(TRANS_DATE) AS MIN_TRANS_DATE
FROM posthis
GROUP BY CLIENTID
) t2
ON t1.CLIENTID = t2.CLIENTID AND
t1.TRANS_DATE = t2.MIN_TRANS_DATE
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?
select purchase_id ,
(case when (select source_type from dbo.tbl_Purchase where purchase_id = tbl_Purchase.purchase_id)=1 then
(select vessel_name from dbo.tbl_Vessel where vessel_type=1)
when (select source_type from dbo.tbl_Purchase where purchase_id = tbl_Purchase.purchase_id)=2 then
(select vessel_name from dbo.tbl_Vessel where vessel_type=2)
else
(select jetty_name from dbo.tbl_Jetty )
end ) as vessl_name
from tbl_Purchase
I think you just want something like this:
select purchase_id ,
COALESCE(v.vessel_name,j.jetty_name) as vessl_name
from dbo.tbl_Purchase p
left join
dbo.tbl_Vessel v
on
p.source_type in (1,2) and
v.vessel_type = p.source_type
left join
dbo.tbl_Jetty j
on
p.source_type not in (1,2)
Otherwise, if you're wanting to continue down your CASE/subquery path, you need to fix these statements:
(select source_type from dbo.tbl_Purchase where purchase_id = tbl_Purchase.purchase_id)
where both sides of that comparison are in fact referencing the same table and the same column, and so it will always return all rows from tbl_Purchase (except those with a NULL purchase_id)
See the query above for how to use aliases (p, v, j) on tables so that you can specify which the correct source table is for each column reference. I.e. I'd expect something like:
(select source_type from dbo.tbl_Purchase p2 where p2.purchase_id = p1.purchase_id)
Assuming that the original tbl_Purchase in the outer FROM clause has been given the alias p1.
Further reading:
COALESCE, Using Joins
You have to remove last subquery from the main query and use join instead of
subquery .
My MySQL table looks like the following:
I would like to get results where all the followings are satisfied:
form_id is 1
sort by lead_id high to low
field_number 9 for that lead_id must be 111
In summary, my query should return 9 rows. Is that possible?
Here is my attempt so far, but I really want to avoid using GROUP_CONCAT if at all possible to get a cleaner result set.
SELECT lead_id, GROUP_CONCAT(field_number, "|", value SEPARATOR "----") AS `values`
FROM lead_detail
WHERE form_id = 1
GROUP BY lead_id
ORDER BY lead_id DESC
If you are meaning that you want to include only rows for a lead_id if there exists a row for that lead_id with field_number=9 and value=111. And otherwise, all rows for that lead_id should be excluded...
You could do something like this:
SELECT d.id
, d.lead_id
, d.form_id
, d.field_number
, d.value
FROM ( SELECT e.lead_id
FROM lead_detail e
WHERE e.form_id = 1
AND e.field_number = 9
AND e.value = 111
GROUP BY e.lead_id
) f
JOIN lead_detail d
ON d.lead_id = f.lead_id
AND d.form_id = 1
ORDER BY d.lead_id DESC
The inline view (aliased as f) returns a distinct list of lead_id that meet specific criteria. We can reference the result from that like it were a table, and use that in a JOIN operation, to return "matching" rows from the lead_detail table. (If there's no row with value=111, field_number=9, and form_id=1 for a particular lead_id, then the inline view won't return that lead_id in the list.)
As another alternative, we could use an EXISTS predicate with a correlated subquery, but this may not perform as well:
SELECT d.id
, d.lead_id
, d.form_id
, d.field_number
, d.value
FROM lead_detail d
WHERE d.form_id = 1
AND EXISTS
( SELECT 1
FROM lead_detail e
WHERE e.form_id = 1
AND e.field_number = 9
AND e.value = 111
AND e.lead_id = d.lead_id
)
ORDER BY d.lead_id DESC
That essentially says, for every row from lead_detail run the subquery following the EXIST keyword... if the subquery returns one (or more) rows, then the EXISTS predicate returns TRUE, otherwise it returns FALSE. That subquery is "correlated" to the outer query, by a predicate in the WHERE clause, matching the lead_id to the value of lead_id from the row from the outer query.
The short answer is "not easily." There are a couple of ways to do this that aren't super straightforward -- probably the easiest is with a sub-query (the exact format will change depending on the exact format of your table, etc.)
SELECT lead_id, GROUP_CONCAT(field_number, "|", value SEPARATOR "----") AS `values`
FROM lead_detail
WHERE `form_id` = 1
AND `lead_id` = (SELECT `lead_id` FROM `lead_detail` WHERE `field_number` = 9 AND `value` = 111 AND `form_id` = 1) /*This is the subquery*/
GROUP BY lead_id
ORDER BY lead_id DESC
Other options include running two separate queries, one to pull the form_id (or form_ids) in question, the other to pull all data for that form_id (or those form_ids).