Upon running this query, the COUNT function doesn't filter by the 'check_if_new_customer' flag. I read in this article: http://dev.mysql.com/tech-resources/articles/wizard/page4.html that SUM can be used instead of COUNT in some cases to get more accurate results, however when I try that, I get something very different, it seems to show massive doubling of numbers. I think this may be because I'm summing the UUID that is in the id field instead of counting at that point. Any suggestions on what I could put there to get a count of all of the existing customers vs the new customers?
SELECT
YEAR(so.date_entered),
so.technical_address_country,
so.technical_address_state,
COUNT(so.id) as all_sales,
COUNT(mf.id) as all_jobs,
SUM(so.total_value) as all_value,
COUNT(IF(so.check_if_new_customer=1,so.id,0)) as sales_order_new,
SUM(IF(so.check_if_new_customer = 1,so.total_value,0)) as total_value_new,
COUNT(IF(so.check_if_new_customer=1,mf.id,0)) as jobs_new,
COUNT(IF(so.check_if_new_customer=0,so.id,0)) as sales_order_existing,
SUM(IF(so.check_if_new_customer = 0,so.total_value,0)) as total_value_existing,
COUNT(IF(so.check_if_new_customer=0,mf.id,0)) as jobs_existing,
SUM(IF(so.check_if_new_customer=0,mf.id,0)) as jobs_existing_t
FROM
sugarcrm2.so_order so
LEFT JOIN
sugarcrm2.mf_job mf on so.id = mf.sales_order_id
WHERE
so.date_entered > "2011-10-30" AND
so.technical_address_country IS NOT NULL AND
so.technical_address_state IS NOT NULL AND
so.deleted = 0 AND
so.has_been_promoted = 1
GROUP BY
YEAR(so.date_entered),
so.technical_address_country,
so.technical_address_state
ORDER BY
so.technical_address_country, so.technical_address_state
If you want to use SUM() like COUNT() you will need to pass it either a 1 or 0 so that all of the 1's will sum up to your desired count. So in your example, if you want a sum of all the new jobs you would do this:
SUM(IF(so.check_if_new_customer=1,1,0)) as jobs_new
or if so.check_if_new_customer always returns a 1 or 0 you could alternatively do this:
SUM(so.check_if_new_customer) as jobs_new
COUNT() returns the number of records for which its argument, if specified, is non NULL. Since its argument in this case is the result of an IF() expression (which evaluates to some column's value if true and 0 if false), virtually every record will be counted irrespective of the test condition.
SUM(), as its name suggest, sums the values of its argument. In this case, it would sum the values of the referenced column whenever the test condition is true.
Apparently neither is what you're after, although your question is rather ambiguous as to what exactly you do want. At a guess, you might want something like:
SUM(so.check_if_new_customer)
I want to sum +1 for every time the joined table's id field is not null.
SUM(IF(so.check_if_new_customer=0 AND mf.id IS NOT NULL,1,0)) as jobs_existing
Related
I have problem with receiving rows if id from one table dont match second one.
If zamowienia.id_telefon is null or dont match i dont recive whole row.
I want to instead get column crm2018.telefon.numer with "0" or null value. Please help :)
I tried something like that but its obvious syntax eror:
SELECT
crm2018.zamowienia.*,
crm2018.telefon.numer
FROM
crm2018.zamowienia
JOIN crm2018.telefon
WHERE
if (zamowienia.id_telfon != "0") zamowienia.id_telefon = telefon.id_telefon else crm2018.telefon.numer as "0"
Here's working code but with missing rows.
SELECT
crm2018.zamowienia.*,
crm2018.telefon.numer
FROM
crm2018.zamowienia
JOIN crm2018.telefon
WHERE
zamowienia.id_telefon = telefon.id_telefon
Just use LEFT JOIN instead of (INNER) JOIN.
Accordingly, you need to move the join condition from the WHERE clause to the ON clause of the join, to avoid filtering out unmatched records. Please note that as it is, your query has a JOIN without ON clause : this is a syntax error in all SQL dialects.
Finally, I would recommend using table aliases in the query : this makes it easier to read and to maintain.
SELECT
z.*,
t.numer
FROM
crm2018.zamowienia AS z
LEFT JOIN crm2018.telefon AS t
ON z.id_telefon = t.id_telefon
When no record is available in crm2018.telefon for the given crm2018.zamowienia, the record will still be displayed, with all columns coming from crm2018.telefon showing NULL values.
If needed, you can turn NULL values to 0 with the COALESCE() function, like :
COALESCE(t.numer, 0)
Before anyone says, I have searched through for a suitable answer for my issue but cannot find anything specific enough so I thought I'd ask it.
Basically I am trying to select a bunch of data for a report of people who have made loan applications to a website, but there are two different types: unsecured and guarantee. I need to place an IFNULL statement in the WHERE clause so that I ONLY use that clause if a certain other field isn't null.
Here is my statement:
SELECT
la.`lms_loan_application_id`,
la.`created`,
la.`updated`,
la.`loan_amount`,
la.`loan_term`,
la.`loan_document_fee`,
la.`broker_reference`,
la.`broker_sub_reference`,
laa.`first_name`,
laa.`surname`,
laa.`dob`,
laa.`email`,
laa.`mobile_number`,
laaAd.`address_postcode`,
lag.`first_name`,
lag.`surname`,
lag.`dob`,
lag.`email`,
lag.`mobile_number`,
lagAd.`address_postcode`,
lagAd.`housing_status`
FROM
loan_application AS la
JOIN
loan_application_applicant AS laa ON la.`id` = laa.`loan_application`
LEFT JOIN
loan_application_guarantor AS lag ON la.`id` = lag.`loan_application`
JOIN
loan_application_address AS laaAd ON laaAd.`loan_application_applicant` = laa.`id`
LEFT JOIN
loan_application_address AS lagAd ON lagAd.`loan_application_guarantor` = lag.`id`
WHERE
la.`status` = 'signature_given'
AND ! IFNULL(lag.`first_name`,
lag.`status` = 'signature_given')
AND laa.`status` = 'signature_given'
AND ! IFNULL(lag.`first_name`,
lagAd.`current_address` = 1)
AND laaAd.`current_address` = 1
ORDER BY la.`updated` DESC
LIMIT 10000
As you can see, I have attempted to use the IFNULLs (although in a negated way, which I assume works?) but all I get is duplicate row results and not the result set I really want.
Basically, I need to use the where clause "lag.status = 'signature_given" and "lagAd.current_address = 1" ONLY if the lag.first_name field is NOT null (i.e. there is a guarantor name) otherwise the status won't exist, and therefore the results of unsecured loans will not show. Hope I'm explaining this well enough!
In summary, I need to show all loan information, unsecured and guaranteed, and use a negated IFNULL in order to determine when the WHERE clause is to be taken into consideration.
Any help appreciated!
Thank you in advance
Michael
From this MySQLTutorial article:
Notice that you should avoid using the IFNULL function in the WHERE clause, because it degrades the performance of the query. If you want to check if a value is NULL or not, you can use IS NULL or IS NOT NULL in the WHERE clause.
Here is a WHERE clause which implements your logic correctly using IS NULL and IS NOT NULL instead of IFNULL:
WHERE la.`status` = 'signature_given' AND
(lag.`first_name` IS NULL OR
(lag.`first_name` IS NOT NULL AND lag.`status` = 'signature_given')) AND
laa.`status` = 'signature_given' AND
(lag.`first_name` IS NULL OR
(lag.`first_name` IS NOT NULL AND lagAd.`current_address` = 1)) AND
laaAd.`current_address` = 1
I hava two very similar queries, however they return different result.
The first one:
select * from products p
where p.val >= 999999 and
not exists
(select * from products p2 where p2.val < 999999 and p.user_id = p2.user_id);
The second one:
select * from products p
where p.val >= 999999 and
p.user_id not in (select user_id from products p2 where p2.val < 999999);
The first one gave me the right answer, while the second one gave me no (zero) result. Is it possible that this happened because the subquery in the second query gave too many results?
Beware of nulls!
If there's a NULL in the sub-query, the NOT IN will not work as most people expect.
The issue will be clearer if you translate NOT IN (...) either to NOT (... OR ...) or to NOT ... AND NOT ... and apply the three-valued logic to the resulting expression.
To illustrate this with an example, let's say the condition is NOT IN (1, 2, NULL) and the row being checked has a value of 3.
Using NOT (... OR ...) you get this:
NOT (3=1 OR 3=2 OR 3=NULL)
The first two conditions in the brackets are false the last one is unknown. Based on the three-valued logic, the result of the disjunction will be unknown. Inversion of an unknown is also unknown, according to that same logic. The result of unknown in a WHERE clause is treated same as the result of false, i.e. a no-match. So, here you are.
Now, if you rewrite the NOT IN with NOT ... AND NOT ..., this is what you get:
NOT 3=1 AND NOT 3=2 AND NOT 3=NULL
The first two terms are true, the last one is unknown (3=NULL is unknown, its inversion is unknown as well). Again, the three-valued logic says the final result is unknown in this case. Here you are again.
So, when a row has a value that is not in the subset but the subset also contains nulls, either do not use NOT IN or filter out the nulls.
I'm trying to get all the data from the match table, along with the currently signed up gamers of each type, experienced or not.
Gamers
(PK)Gamer_Id
Gamer_firstName,
Gamer_lastName,
Gamer experience(Y/N)
Gamer_matches
(PK)FK GamerId,
(PK)FK MatchId,
Gamer_score
Match
(PK)Match_Id,
ExperiencedGamers_needed,
InExperiencedGamers_needed
I've tried this query along with many others but it doesn't work, is it a bad join?
SELECT M.MatchId,M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
(SELECT COUNT(GM.GamerId)
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "Y"
AND GM.MatchId = M.MatchId
GROUP BY GM.MatchId)AS ExpertsSignedUp,
(SELECT COUNT(GM.GamerId)
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "N"
AND GM.MatchId = M.MatchId
GROUP BY GM.MatchId) AS NovicesSignedUp
FROM MATCHES M
What you've written is called a correlated subquery which forces SQL to re-execute the subquery for each row fetched from Matches. It can be made to work, but it's pretty inefficient. In some complex queries it may be necessary, but not in this case.
I would solve this query this way:
SELECT M.MatchId, M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
SUM(G.experience = 'Y') AS ExpertsSignedUp,
SUM(G.experience = 'N') AS NovicesSignedUp
FROM MATCHES M
LEFT OUTER JOIN (Gamer_matches GM
INNER JOIN Gamers G ON G.GamerId = GM.GamerId)
ON M.MatchId = GM.MatchId
GROUP BY M.MatchId;
Here it outputs only one row per Match because of the GROUP BY at the end.
There's no subquery to re-execute many times, it's just joining Matches to the respective rows in the other tables once. But I use an outer join in case a Match has zero players of eithe type signed up.
Then instead of using COUNT() I use a trick of MySQL and use SUM() with a boolean expression inside the SUM() function. Boolean expressions in MySQL always return 0 or 1. The SUM() of these is the same as the COUNT() where the expression returns true. This way I can get the "count" of both experts and novices only scanning the Gamers table once.
P.S. MySQL is working in a non-standard way to return 0 or 1 from a boolean expression. Standard ANSI SQL does not support this, nor do many other brands of RDBMS. Standardly, a boolean expression returns a boolean, not an integer.
But you can use a more verbose expression if you need to write standard SQL for portability:
SUM(CASE G.experience WHEN 'Y' THEN 1 WHEN 'N' THEN 0 END) AS ExpertsSignedUp
Not quite sure what I'm missing, but my SQL statement is only returning one row.
SELECT
tl.*,
(tl.topic_total_rating/tl.topic_rates) as topic_rating,
COUNT(pl.post_id) - 1 as reply_count,
MIN(pl.post_time) AS topic_time,
MAX(pl.post_time) AS topic_bump
FROM topic_list tl
JOIN post_list pl
ON tl.topic_id=pl.post_parent
WHERE
tl.topic_board_link = %i
AND topic_hidden != 1
ORDER BY %s
I have two tables (post_list and topic_list), and post_list's post_parent links to a topic_list's topic_id.
Instead of returning all the topics (where their board's topic_board_link is n), it only returns one topic.
You would normally need a GROUP BY clause in there. MySQL has different rules from Standard SQL on the subject of when GROUP BY is needed. This is therefore closer to Standard SQL:
SELECT tl.*,
(tl.topic_total_rating/tl.topic_rates) AS topic_rating,
COUNT(pl.post_id) - 1 AS reply_count,
MIN(pl.post_time) AS topic_time,
MAX(pl.post_time) AS topic_bump
FROM topic_list AS tl
JOIN post_list AS pl ON tl.topic_id = pl.post_parent
WHERE tl.topic_board_link = ? -- %i
AND tl.topic_hidden != 1
GROUP BY tl.col1, ..., topic_rating
ORDER BY ? -- %s
In Standard SQL, you would have to list every column in topic_list, plus the non-aggregate value topic_rating (and you might have to list the expression rather than the display label or column alias in the select list).
You also have a restriction condition on 'topic_board_link' which might be limiting your result set to one group. You cannot normally use a placeholder in the ORDER BY clause, either.