How to implement WHERE conditions in LEFT_JOIN. My query is:
SELECT t1.company_short_name, COUNT(t2.user_ip_address) as chart_accessed
FROM tblcompanymaster t1
LEFT JOIN tblhistorymaster t2 ON t1.row_id = t2.company_id
WHERE t2.user_last_request_time BETWEEN 1603775329 AND 1606280929
GROUP BY t1.company_short_name
Where I need to found all the company_short_name with the count of access, and if there is no access or the count is 0 then it should come COUNT(t2.user_ip_address) is 0. When I am not using where condition its working perfectly but after the use of where condition its giving only the result where the count is greater then 1. I have tried a lot but I am not able to modify the code. Any suggestions will be of great help
Put your where clause condition to ON clause
SELECT t1.company_short_name, COUNT(t2.user_ip_address) as chart_accessed
FROM tblcompanymaster t1
LEFT JOIN tblhistorymaster t2 ON t1.row_id = t2.company_id
and t2.user_last_request_time BETWEEN 1603775329 AND 1606280929
GROUP BY t1.company_short_name
You can add the filtering (where) component to the join instead - only taking the values if they exist in t2.
SELECT t1.company_short_name, COUNT(t2.user_ip_address) as chart_accessed
FROM tblcompanymaster t1
LEFT JOIN tblhistorymaster t2 ON t1.row_id = t2.company_id AND t2.user_last_request_time BETWEEN 1603775329 AND 1606280929
GROUP BY t1.company_short_name
Related
Thanks for looking at my post, any help/guidance is appreciated. My SQL skills are lacking and I have tried several solutions without success. Anyway, I need to create a VIEW for the following query:
CREATE VIEW open_orders AS
SELECT
t1.orderID,
DATE_FORMAT(t1.orderDate,'%m-%d-%Y') AS orderDate,
t6.colorName,
t1.originID,
t1.rackNumber,
t2.locationNumber AS originNumber,
t2.locationName AS originName,
t3.locationName AS destinationName,
t4.locationStatusName,
COUNT(t5.orderID) AS totalCount
FROM `order` AS t1
JOIN `location` AS t2 ON t1.originID = t2.locationID
JOIN `location` AS t3 ON t1.destinationID = t3.locationID
JOIN `locationStatus` AS t4 ON t1.locationStatusID = t4.locationStatusID
LEFT JOIN (SELECT * FROM `orderItem` WHERE `productStatusID` = 02 OR `productStatusID` = 03) AS t5 ON t1.orderID = t5.orderID
JOIN `color` AS t6 ON t1.requestedColorID = t6.colorID
WHERE t1.orderStatusID = 01
GROUP BY t1.orderID
ORDER BY t1.orderDate DESC, t1.orderID DESC;
The problem is with the subquery. Because I can't use a subquery within the FROM statement I attempted to use a VIEW. However, the table is large and this approach causes too much of a performance issue.
I'm sure there is a way I can accomplish this without using a VIEW or subquery but am having trouble coming up with a solution.
Any help/guidance is appreciated.
You don't need a subquery.
...
LEFT JOIN orderItem AS t5
ON t5.orderID = t1.orderID
AND t5.productStatusID IN (02,03)
JOIN color ...
This does the same thing as your query, but more efficiently since it avoids the derived table.
I have two tables: terems and logs1015.
Need to add data from logs1015 to terems based on similar 'hash' row.
This query works fine if 'SUM(insum)' or 'SUM(outsum) is larger than 0.
But if logs1015 doesn't contain data with such 'hash' then query result is empty.
What the mistake? Thanks
SELECT terems.*,
SUM(insum) as firstsum ,
SUM(outsum) as secondsum
FROM terems
LEFT JOIN logs1015 USING(hash)
WHERE owner='1'
AND (type='stat')
AND (time BETWEEN 1445904000 AND 1445990400)
GROUP BY name
LIMIT 1000
Tables structure
*terems*: id(int),hash(varchar),name(varchar),owner(int)
*logs1015*: id(int),hash(varchar),type(varchar),insum(int),outsum(int),time(varchar)
When (left) outer joining, you must put the where clauses on the outer table in the join condition, otherwise you say that it must exist after joining. And then you have implicitly turned it into an inner join.
Also use aliases on your tables so you can easily spot these bugs.
Example:
SELECT t.name,
SUM(l.insum) as firstsum ,
SUM(l.outsum) as secondsum
FROM terems t
LEFT JOIN logs1015 l ON t.hash = l.hash
AND (l.type='stat')
WHERE t.owner='1'
AND (t.time BETWEEN 1445904000 AND 1445990400)
GROUP BY t.name
LIMIT 1000
Working solution:
"SELECT t.*,
SUM(l.insum) as firstsum ,
SUM(l.outsum) as secondsum
FROM terems t
LEFT JOIN logs1015 l ON
t.hash = l.hash
AND (l.type='stat')
AND (l.time BETWEEN $fromstamp AND $tostamp)
WHERE t.owner='$userid'
GROUP BY t.name
LIMIT 1000";
Thanks a lot!
I have query that working perfectly.but now there is situation where i have to join 2 query in case statement.but problem is one of the query is in already use.So my question how do i add this two sql in one sql
My original sql is
SELECT
tc.dentist_id,md.vendor_no,pl.pack_trans_id,tc.agent_dentist,md.company_name,md.contact,md.phone_no,sql1.image_path,sql1.metal_id,sql1.expect_more,sql1.how_long_acquire,tc.check_amt,tc.check_date_sent,tc.check_no
FROM tbl_check tc
LEFT JOIN tbl_mst_dentist md ON tc.dentist_id=md.dentist_id
LEFT JOIN tbl_pack_list pl ON tc.pack_id=pl.pack_id
LEFT JOIN (SELECT image_path,pack_id,metal_id,expect_more,how_long_acquire FROM
tbl_metals_list GROUP BY pack_id
)sql1 ON tc.pack_id=sql1.pack_id
WHERE tc.sale_agent_id = '3' AND tc.paying_percent !=0
Now i have to add 2 sql statement in the above statement
if(tc.agent_dentist=a) select sa.* ,sm.state_code from tbl_sales_agent
as sa,tbl_mst_state as sm where sa.sales_agent_id = '3' AND
sa.state=sm.state_name else select * from tbl_mst_dentist where
dentist_id =tc.dentist_id
second table already is in use.Is it possible? Thanks in advance
yes, you can use an ALIAS with a different name. E.g. TABLE AS ANY_ALIAS.
SELECT *
FROM t1
JOIN t2 AS alias_a ON (alias_a.t1_id = t1.id)
JOIN t2 AS alias_b ON (alias_b.t1_id = t1.id)
Note that in the absence of any aggregating functions, the use of GROUP BY in this query...
SELECT image_path
, pack_id
, metal_id
, expect_more
, how_long_acquire
FROM tbl_metals_list
GROUP
BY pack_id
...makes little sense. Perhaps you meant SELECT DISTINCT...?
I want to replace the subquery with a join, if possible.
SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON fftenant_surveyanswer.surveyquestion_id = 1
AND fftenant_surveyanswer.`surveyresult_id` IN (SELECT y.`surveyresult_id` FROM `fftenant_farmer_surveyresults` y WHERE y.farmer_id = `fftenant_farmer`.`person_ptr_id`)
I tried:
SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_farmer_surveyresults`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`)
AND fftenant_surveyanswer.surveyquestion_id = 1
But that gave me one record per farmer per survey result for that farmer. I only want one record per farmer as returned by the first query.
A join may be faster on most RDBMs, but the real reason I asked this question is I just can't seem to formulate a join to replace the subquery and I want to know if it's even possible.
You could use DISTINCT or GROUP BY, as mvds and Brilliand suggest, but I think it's closer to the query's design intent if you change the last join to an inner-join, but elevating its precedence:
SELECT farmer.person_ptr_id, surveyanswer.text_value
FROM fftenant_farmer AS farmer
INNER
JOIN fftenant_person AS person
ON person.id = farmer.person_ptr_id
LEFT
OUTER
JOIN
( fftenant_farmer_surveyresults AS farmer_surveyresults
INNER
JOIN fftenant_surveyanswer AS surveyanswer
ON surveyanswer.surveyresult_id = farmer_surveyresults.surveyresult_id
AND surveyanswer.surveyquestion_id = 1
)
ON farmer_surveyresults.farmer_id = farmer.person_ptr_id
Broadly speaking, this will end up giving the same results as the DISTINCT or GROUP BY approach, but in a more principled, less ad hoc way, IMHO.
Use SELECT DISTINCT or GROUP BY to remove the duplicate entries.
Changing your attempt as little as possible:
SELECT DISTINCT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_farmer_surveyresults`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`)
AND fftenant_surveyanswer.surveyquestion_id = 1
the real reason I asked this question is I just can't seem to formulate a join to replace the subquery and I want to know if it's even possible
Then consider a much simpler example to begin with e.g.
SELECT *
FROM T1
WHERE id IN (SELECT id FROM T2);
This is known as a semi join and if desired may be re-written using (among other possibilities) a JOIN with a SELECT clause to a) project only from the 'outer' table, and b) return only DISTINCT rows:
SELECT DISTINCT T1.*
FROM T1
JOIN T2 USING (id);
I've got a query as follows:
SELECT COUNT(Table1.Identifier) AS NonCancelCnt
FROM Table1, Table2
LEFT JOIN eventattendees ON eventattendees.AttendeeID = 47322
LEFT JOIN eventsignup ON eventattendees.AttendeeID = eventsignup.AttendeeID
LEFT JOIN transactions on transactions.registrationID=eventsignup.regid
WHERE ((eventsignup.EventID = Table1.Identifier) Or (eventsignup.EventID = Table1.AttendanceLinkID))
The "OR" clause is causing no index to be used. If I remove either portion, my execution path goes from 95,000 to 200, and speed is drastically increased.
I'm not very experienced in reworking such a thing, what is my best option for doing so?
First, you should rewrite your query to specify how Table1, Table2 and eventattendees are joined. Also choose whether you want to specify the columns to use to join in the WHERE clause or after the JOIN keyword. After you clean it up a bit, the optimizer may do a better job of picking the proper index to use.
If that still doesn't work, you can use a SQL hint to specify the index you want the optimizer to use:
WITH INDEX(IX_nameofindex)
SELECT COUNT(Table1.Identifier) AS NonCancelCnt
FROM Table1, Table2
LEFT JOIN eventattendees ON eventattendees.AttendeeID = 47322
LEFT JOIN eventsignup ON eventattendees.AttendeeID = eventsignup.AttendeeID
LEFT JOIN transactions on transactions.registrationID=eventsignup.regid
WHERE eventsignup.EventID = Table1.AttendanceLinkID
union all
SELECT COUNT(Table1.Identifier) AS NonCancelCnt
FROM Table1, Table2
LEFT JOIN eventattendees ON eventattendees.AttendeeID = 47322
LEFT JOIN eventsignup ON eventattendees.AttendeeID = eventsignup.AttendeeID
LEFT JOIN transactions on transactions.registrationID=eventsignup.regid
WHERE eventsignup.EventID = Table1.Identifier
Not understanding what Table1 and Table2 are, nor are they joined in any shape, you will get a Cartesian result (for each record in Table1, will be joined with each record in Table2)
Additionally, your where clause could just be simplified with an IN clause
where
eventsignup.EventID IN ( Table1.Identifier, Table1.AttendanceLinkID )