I've read loads of answers on SO, but still can't get this to work. I'm pretty sure I need a subquery but don't know where I should begin...
Here's readable/psuedo of what i want to do:
SELECT DISTINCT cat_sub.*, COUNT(job.job_id) AS num_properties_which_meet_criteria
FROM cat_sub
LEFT JOIN job_cat USING (sc_id)
LEFT JOIN job USING (job_id)
WHERE job.village_id=2 AND num_properties_which_meet_criteria > 0
GROUP BY sc_id
I'm trying to make my WHERE reference the amount of valid results in the job table, which in this instance are those which matchjob.village_id=2.
So just to make clear, i don't want the total number of rows matched by the join. I want to total num rows matched by the join and meeting the WHERE criteria.
Really appreciate any help!
You test the value of an aggregate function with a HAVING clause.
SELECT DISTINCT cat_sub.*, COUNT(job.job_id) AS num_properties_which_meet_criteria
FROM cat_sub
LEFT JOIN job_cat USING (sc_id)
LEFT JOIN job USING (job_id)
WHERE job.village_id=2
GROUP BY sc_id
HAVING COUNT(job.job_id) > 0
Use having instead of where:
WHERE job.village_id=2
GROUP BY sc_id
HAVING num_properties_which_meet_criteria > 0
You need to have a "HAVING" clause, there you can use conditions on aggregate functions used in the SELECT part of the query.
Did you try:
SELECT DISTINCT cat_sub.*, COUNT(job.job_id)
FROM cat_sub
LEFT JOIN job_cat USING (sc_id)
LEFT JOIN job USING (job_id)
WHERE job.village_id=2
GROUP BY sc_id
HAVING COUNT(job.job_id) > 0
UPDATE: Removed alias
Related
I have two tables pdc and class
select roll_no as roll,sum(pdc.amount) as amount,count(amount) as given,
stu_profile.name,f_name,scholarship,class_id,batch_id,statuss
from stu_profile left join
pdc
on pdc.roll=stu_profile.roll_no
where 1 and class_id!='' and given=0
group by roll
I want a condition on count (amount) column
Use having clause instead
. . .
having count(amount) = 0;
Then answer to your question is the having clause. But, your query is malformed and would not work in most databases, including the more recent versions of MySQL.
The solution is simple: In an aggregation query, the only columns in the SELECT should be the GROUP BY keys or arguments to aggregation functions.
Let me assume that you want:
select p.roll_no as roll, sum(pdc.amount) as amount,
count(pdc.amount) as given,
p.name, p.f_name, p.scholarship, p.class_id, p.batch_id, p.statuss
from stu_profile p left join
pdc
on pdc.roll = p.roll_no
where 1 and class_id <> ''
group by roll, p.name, p.f_name, p.scholarship, p.class_id, p.batch_id, p.statuss
You can then just add something like:
having given = 0
I have one SQL query with INNER JOINS. I need to get all offers from table offers.
Table offers is empty now. But the following query returns one row with NULL field.
Why is it returned? How to fix that? I need to return 0 rows if table is empty.
Query:
select *, SUM(offers.price * announcement_product.amount) AS total, announcements.user_id AS creator_ann, announcements.id AS ann_id,
announcements.delivery AS deliveryAnn, announcements.payment AS
paymentAnn, SUM(announcement_product.amount) AS amount,
announcement_product.name as name_product
from `offers`
inner join `announcements` on `announcements`.`id` = `offers`.`announcement_id`
inner join `announcement_product` on `offers`.`announcement_product_id` = `announcement_product`.`id`
inner join `countries` on `countries`.`id` = `announcements`.`country`
where `offers`.`user_id` = 1 and `offers`.`status` = 1 and `offers`.`deleted_at` is null
You're using the aggregate function SUM(), but you don't have any GROUP BY clause.
When you do that you are instructing MySQL to add up all the row values in the column you mention in SUM(). It will do that even if there are no rows to add up.
For best results you should study up on the GROUP BY function and how to use it with SUM(). It's hard to guess what you want from your query.
I'm not sure, but I don't think
select *, ..
when there's multiple tables in the query is valid.
Try
select offers.*,..
This how Your select structure should be :
Select
Id,
Sku,
Sum(Onhand),
Sum(price)
From mytable
Where mytable Onhand > 0
Group by
Id,Sku
If you are going to use aggregate function such as Max,Sum,Min,....
you need to use group by for other table fields that your using in the select part.
I'm completely new to SQL. I have a table with multiple rows for the same ID (Alpha_code).
I want to query this table to provide only 1 row for each Alpha_code.
I need it to first select the newest row if rows have been added on different (contact_date).
I have found the statement below does this no problem.
SELECT m.*
FROM (SELECT Alpha_code, max(Contact_date) AS MaxDate FROM contactsNTH GROUP BY Alpha_code)
AS mm INNER JOIN contactsNTH AS m ON (mm.MaxDate = m.Contact_Date) AND (mm.Alpha_code = m.Alpha_code)
However there are other multiple rows that were entered on the same (contact_date). I'm not sure how to add more code to then only show 1 of the multiple rows remaining.
I've tried the Select Distinct statement but it didn't work.
Any assistance would be appreciated. If I can answer this myself in the meantime I'll post the answer
thanks, shaun
This thread is close to what I'm asking but I find the answer confusing.
How To Select Distinct Row Based On Multiple Fields 4
Assuming your schema as given here :- http://sqlfiddle.com/#!2/4e6ff/2
You can use the following query
SELECT c1.Alpha_code,c1.Contct_date from contactsNTH as c1
LEFT JOIN
contactsNTH as c2
ON
c1.Alpha_code = c2.Alpha_code
AND
(c1.Contct_date > c2.Contct_date) group by c1.Alpha_code
This query doesn't works in Standard SQL because it says, "a query that includes a GROUP BY clause cannot refer to non aggregated columns in the select list that are not named in the GROUP BY clause"
Try using this query
SELECT c1.Alpha_code,MAX(c1.Contct_date) as contact_date from contactsNTH as c1
LEFT JOIN
contactsNTH as c2
ON
c1.Alpha_code = c2.Alpha_code
AND
(c1.Contct_date > c2.Contct_date) group by c1.Alpha_code
both will provide the same result http://sqlfiddle.com/#!2/4e6ff/4
You can do it easily by using inner query. Sql Fiddle Demo
SELECT Alpha_code, Contact_date AS MaxDate FROM contactsNTH AS t WHERE
Contact_date = (SELECT MAX(Contact_date) FROM contactsNTH
WHERE Alpha_code=t.Alpha_code)
I wrote a query using simply group by and having maximum date but it failed Then I wrote these words in google select group by having max and found the result. this is an example guide for you to get such problems fixed quickly
I have a mysql query and it works fine when i use where clause, but when i donot use
where clause it gone and never gives the output and finally timeout.
Actually i have used Explain command to check the performance of the query and in both cases the Explain gives the same number of rows used in joining.
I have attached the image of output got with Explain command.
Below is the query.
I couldn't figure whats the problem here.
Any help is highly appreciated.
Thanks.
SELECT
MCI.CLIENT_ID AS CLIENT_ID, MCI.NAME AS CLIENT_NAME, MCI.PRIMARY_CONTACT AS CLIENT_PRIMARY_CONTACT,
MCI.ADDED_BY AS SP_ID, CONCAT(MUD_SP.FIRST_NAME, ' ', MUD_SP.LAST_NAME) AS SP_NAME,
MCI.FK_PROSPECT_ID AS PROSPECT_ID, MCI.DATE_ADDED AS ADDED_ON,
(SELECT GROUP_CONCAT(LT.TAG_TEXT SEPARATOR ', ')
FROM LK_TAG LT
INNER JOIN M_OBJECT_TAG_MAPPING MOTM
ON LT.PK_ID = MOTM.FK_TAG_ID
WHERE MOTM.FK_OBJECT_ID = MCI.FK_PROSPECT_ID
AND MOTM.OBJECT_TYPE = 1
AND MOTM.IS_ACTIVE = 1
) AS TAGS,
IFNULL(SUM(GET_DIGITS(MMR.RCP_AMOUNT)), 0) AS REVENUE_SO_FAR,
IFNULL(SUM(GET_DIGITS(MMR.RCP_RUPEES)), 0) AS REVENUE_INR,
COUNT(DISTINCT PMI_MONTHLY.PROJECT_ID) AS MONTHLY,
COUNT(DISTINCT PMI_FIXED.PROJECT_ID) AS FIXED,
COUNT(DISTINCT PMI_HOURLY.PROJECT_ID) AS HOURLY,
COUNT(DISTINCT PMI_ANNUAL.PROJECT_ID) AS ANNUAL,
COUNT(DISTINCT PMI_CURRENTLY_RUNNING.PROJECT_ID) AS CURRENTLY_RUNNING_PROJECTS,
COUNT(DISTINCT PMI_YET_TO_START.PROJECT_ID) AS YET_TO_START_PROJECTS,
COUNT(DISTINCT PMI_TECH_SALES_CLOSED.PROJECT_ID) AS TECH_SALES_CLOSED_PROJECTS
FROM
M_CLIENT_INFO MCI
INNER JOIN M_USER_DETAILS MUD_SP
ON MCI.ADDED_BY = MUD_SP.PK_ID
LEFT OUTER JOIN M_MONTH_RECEIPT MMR
ON MMR.CLIENT_ID = MCI.CLIENT_ID
LEFT OUTER JOIN M_PROJECT_INFO PMI_FIXED
ON PMI_FIXED.CLIENT_ID = MCI.CLIENT_ID AND PMI_FIXED.PROJECT_TYPE = 1
LEFT OUTER JOIN M_PROJECT_INFO PMI_MONTHLY
ON PMI_MONTHLY.CLIENT_ID = MCI.CLIENT_ID AND PMI_MONTHLY.PROJECT_TYPE = 2
LEFT OUTER JOIN M_PROJECT_INFO PMI_HOURLY
ON PMI_HOURLY.CLIENT_ID = MCI.CLIENT_ID AND PMI_HOURLY.PROJECT_TYPE = 3
LEFT OUTER JOIN M_PROJECT_INFO PMI_ANNUAL
ON PMI_ANNUAL.CLIENT_ID = MCI.CLIENT_ID AND PMI_ANNUAL.PROJECT_TYPE = 4
LEFT OUTER JOIN M_PROJECT_INFO PMI_CURRENTLY_RUNNING
ON PMI_CURRENTLY_RUNNING.CLIENT_ID = MCI.CLIENT_ID AND PMI_CURRENTLY_RUNNING.STATUS = 4
LEFT OUTER JOIN M_PROJECT_INFO PMI_YET_TO_START
ON PMI_YET_TO_START.CLIENT_ID = MCI.CLIENT_ID AND PMI_YET_TO_START.STATUS < 4
LEFT OUTER JOIN M_PROJECT_INFO PMI_TECH_SALES_CLOSED
ON PMI_TECH_SALES_CLOSED.CLIENT_ID = MCI.CLIENT_ID AND PMI_TECH_SALES_CLOSED.STATUS > 4
WHERE YEAR(MCI.DATE_ADDED) = '2012'
GROUP BY MCI.CLIENT_ID ORDER BY CLIENT_NAME ASC
Yes, as many people have said, the key is that when you have the where clause, mysql engine filters the table M_CLIENT_INFO --probably drammatically--.
A similar result as removing the where clause is to to add this where clause:
where 1 = 1
You will see that the performance is degraded also because mysql will try to get all the data.
Remove the where clause and all columns from select and add a count to see how many records you get. If it is reasonable, say up to 10k, then do the following,
put back the select columns related to M_CLIENT_INFO
do not include the nested one "TAGS"
remove all your joins
run your query without where clause and gradually include the joins
this way you'll find out when the timeout is caused.
I would try the following. First, MySQL has a keyword "STRAIGHT_JOIN" which tells the optimizer to do the query in the table order you've specified. Since all you left-joins are child-related (like a lookup table), you don't want MySQL to try and interpret one of those as a primary basis of the query.
SELECT STRAIGHT_JOIN ... rest of query.
Next, your M_PROJECT_INFO table, I dont know how many columns of data are out there, but you appear to be concentrating on just a few columns on your DISTINCT aggregates. I would make sure you have a covering index on these elements to help the query via an index on
( Client_ID, Project_Type, Status, Project_ID )
This way the engine can apply the criteria and get the distinct all out of the index instead of having to go back to the raw data pages for the query.
Third, your M_CLIENT_INFO table. Ensure that has an index on both your criteria, group by AND your Order By, and change your order by from the aliased "CLIENT_NAME" to the actual column of the SQL table so it matches the index
( Date_Added, Client_ID, Name )
I have "name" in ticks as it is also a reserved word and helps clarify the column, not the keyword.
Next, the WHERE clause. Whenever you apply a function to an indexed column name, it doesn't work the greatest, especially on date/time fields... You might want to change your where clause to
WHERE MCI.Date_Added between '2012-01-01' and '2012-12-31 23:59:59'
so the BETWEEN range is showing the entire year and the index can better be utilized.
Finally, if the above do not help, I would consider splitting your query some. The GROUP_CONCACT inline select for the TAGS might be a bit of a killer for you. You might want to have all the distinct elements first for the grouping per client, THEN get those details.... Something like
select
PQ.*,
group_concat(...) tags
from
( the entire primary part of the query ) as PQ
Left join yourGroupConcatTableBasis on key columns
I am trying to perform a query which groups a set of data by an attribute called type_id.
SELECT
vt.id AS voucher_type,
COALESCE(COUNT(v.id), 0) AS vouchers_remaining
FROM
vouchers v
INNER JOIN voucher_types vt
ON vt.id = v.type_id
WHERE
v.sold = 0
GROUP BY vt.id
What I want in the result is the type_id and the number of unsold products remaining for each type. This is working OK provided that there is at least one left, however if there is a zero count row, it is not returned in the result set.
How can I set up a dummy row for those types which do not have any corresponding rows to count?
Any advice would be greatly appreciated.
Thanks
You'll have to use a LEFT JOIN instead of an INNER JOIN. You start by selecting all voucher_types and then left join to find the count.
SELECT
voucher_types.id AS voucher_type,
IFNULL(vouchers_count.vouchers_remaining, 0) AS vouchers_remaining
FROM
voucher_types
LEFT JOIN
(
SELECT
v.type_id AS voucher_type,
COUNT(v.id) AS vouchers_remaining
FROM
vouchers v
WHERE
v.sold = 0
GROUP BY v.type_id
) AS vouchers_count
ON vouchers_count.voucher_type = voucher_types.id
You want an OUTER JOIN (or LEFT JOIN, same difference) instead of an INNER JOIN. That should already do the trick.
Because you're doing an INNER JOIN you automatically exclude types with no corresponding vouchers. You need a RIGHT OUTER JOIN.
Also, as far as I can remember, COUNT will always give you an integer, so there is no need for the COALESCE.
Good luck,
Alin