Mysql query - invalid use of group function - sql

mysql_query("
SELECT
b.id as b_id
FROM
banner b
INNER JOIN
bannerhits bl
ON
b.id = bl.bannerid
AND
bl.userid = '".$this->userid."'
INNER JOIN
bannerhits blog
ON
b.id = blog.bannerid
INNER JOIN
bannerklik bk
ON
b.id = bk.bannerid
WHERE
(
b.placement = '".$place."'
AND
(
b.usertype = '".$usertype."'
OR
b.usertype = ''
)
AND
b.userpostalcode LIKE ',".$postcode.",'
AND
(
b.userage LIKE ',".$ageYears.",'
OR
b.userage IS NULL
)
AND
(
b.maxviewsprday > count(bl.id)
OR
b.maxviewsprday IS NULL
)
AND
b.maxhits > count(blog.id)
AND
b.maxklik > count(bk.id)
".$ubid."
)
OR
remainingshow = '1'
GROUP BY
bl.id,
bk.id,
blog.id
ORDER BY
remainingshow ASC
LIMIT 1
");
Hello.. This tells me, that it is "invalid use of group function" .. what I want to do is to make sure, that when I count my log for clicks and shows of the banner, there has to be fewer rows with the bannerid=b.id in the log, than the fields b.maxklik and b.maxhits says (so I can set e.g. 6000 clicks or 50000 shows for a banner)..
Can you help with a mysql query that should work??
EDIT 2:
Same error
SELECT
bl.id as bl_id,
bk.id as bk_id,
blog.id as blog_id
FROM
banner b
INNER JOIN
bannerhits bl
ON
b.id = bl.bannerid
AND
bl.userid = '".$this->userid."'
INNER JOIN
bannerhits blog
ON
b.id = blog.bannerid
INNER JOIN
bannerklik bk
ON
b.id = bk.bannerid
WHERE
(
b.placement = '".$place."'
AND
(
b.usertype = '".$usertype."'
OR
b.usertype = ''
)
AND
b.userpostalcode LIKE ',".$postcode.",'
AND
(
b.userage LIKE ',".$ageYears.",'
OR
b.userage IS NULL
)
AND
(
b.maxviewsprday > count(bl.id)
OR
b.maxviewsprday IS NULL
)
AND
b.maxhits > count(blog.id)
AND
b.maxklik > count(bk.id)
".$ubid."
)
OR
remainingshow = '1'
GROUP BY
b.id,
bl.id,
bk.id,
blog.id
ORDER BY
remainingshow ASC
LIMIT 1
EDIT 3:
SELECT
b.id as b_id,
b.maxhits as b_maxhits,
b.maxklik as b_maxkli,
b.maxviewsprday as b_maxviewsprday
FROM banner b
JOIN
bannerhits bl
ON
b.id = bl.bannerid
AND
bl.userid = '".$this->userid."'
JOIN
bannerhits blog
ON
b.id = blog.bannerid
JOIN
bannerklik bk
ON
b.id = bk.bannerid
WHERE
(
b.placement = '".$place."'
AND
b.usertype IN ('".$usertype."', '')
AND
b.userpostalcode LIKE ',".$postcode.",'
AND
(
b.userage LIKE ',".$ageYears.",'
OR
b.userage IS NULL
)
AND
b.maxviewsprday IS NULL
)
OR
b.remainingshow = '1'
GROUP BY
bl.id,
bk.id,
blog.id
HAVING
(b.maxhits > count(blog.id) OR b.maxhits = '0')
AND
(b.maxklik > count(bk.id) OR b.maxklik = '0')
AND
(b.maxviewsprday > count(bl.id) OR b.maxviewsprday = '0')
ORDER BY
b.remainingshow ASC
LIMIT
1

You can't use aggregate functions in the WHERE clause - only the HAVING. I did my best to re-write your query as:
SELECT b.id as b_id
FROM BANNER b
JOIN BANNERHITS bl ON b.id = bl.bannerid
AND bl.userid = '".$this->userid."'
JOIN BANNERHITS blog ON b.id = blog.bannerid
JOIN BANNERKLIK bk ON b.id = bk.bannerid
WHERE ( b.placement = '".$place."'
AND b.usertype IN ('".$usertype."', '')
AND b.userpostalcode LIKE ',".$postcode.",'
AND (b.userage LIKE ',".$ageYears.",' OR b.userage IS NULL)
AND b.maxviewsprday IS NULL)
OR remainingshow = '1'
GROUP BY bl.id, bk.id, blog.id
HAVING b.maxhits > count(blog.id)
AND b.maxklik > count(bk.id)
AND b.maxviewsprday > count(bl.id)
ORDER BY remainingshow ASC
LIMIT 1
You appear to have a syntax error here:
AND b.maxklik > count(bk.id) ".$ubid.")
I don't know how you want to incorporate the $ubid variable into the query...

Related

Subquery value bigger than another subquery value

I've got a query which returns 8 columns, 2 of them are sub queries which returns the maximum date. I would like to create 9th column which will return a number, asterisk or something to highlight the rows where date in column 1 is bigger than in column 2 but still keep all the rows. Is it possible somehow?
Edit:
this is the query
The columns I want to see the differences in are MaxExpDateGB and MaxExpDatePH
select
i.ITEM,
i.COMPANY,
count(distinct i.LOGISTICS_UNIT) as LocationsGB,
sum(on_hand_qty) as StockGB,
(select
Count(distinct location)
from
LOCATION_INVENTORY b where b.ITEM = i.ITEM and b.TEMPLATE_FIELD1 = '139' and b.TEMPLATE_FIELD4 is not null and b.TEMPLATE_FIELD5 is null) as LocationsPH,
(select
sum(on_hand_qty)
from
LOCATION_INVENTORY b where b.ITEM = i.ITEM and b.TEMPLATE_FIELD1 = '139' and b.TEMPLATE_FIELD4 is not null and b.TEMPLATE_FIELD5 is null) as StockPH,
MAX(i.Expiration_DATE) as MaxExpDateGB,
(select
MAX(a.Expiration_DATE)
from
LOCATION_INVENTORY a where a.ITEM = i.ITEM and a.TEMPLATE_FIELD1 = '139' and a.TEMPLATE_FIELD4 is not null and a.INVENTORY_STS = 'available' ) as MaxExpDatePH
from
LOCATION l inner join LOCATION_INVENTORY i on l.LOCATION = i.LOCATION inner join ITEM t on i.ITEM = t.ITEM
where
t.USER_DEF6 = '10'
and i.LOCATION = '000-gb-01'
group by
i.item,i.company
Without any refactoring
select *, case when LocationsPH > StockPH then '*' end flag
from (
select
i.ITEM,
i.COMPANY,
count(distinct i.LOGISTICS_UNIT) as LocationsGB,
sum(on_hand_qty) as StockGB,
(select
Count(distinct location)
from
LOCATION_INVENTORY b where b.ITEM = i.ITEM and b.TEMPLATE_FIELD1 = '139' and b.TEMPLATE_FIELD4 is not null and b.TEMPLATE_FIELD5 is null
) as LocationsPH,
(select
sum(on_hand_qty)
from
LOCATION_INVENTORY b where b.ITEM = i.ITEM and b.TEMPLATE_FIELD1 = '139' and b.TEMPLATE_FIELD4 is not null and b.TEMPLATE_FIELD5 is null
) as StockPH,
MAX(i.Expiration_DATE) as MaxExpDateGB,
(select
MAX(a.Expiration_DATE)
from
LOCATION_INVENTORY a where a.ITEM = i.ITEM and a.TEMPLATE_FIELD1 = '139' and a.TEMPLATE_FIELD4 is not null and a.INVENTORY_STS = 'available'
) as MaxExpDatePH
from
LOCATION l
inner join LOCATION_INVENTORY i on l.LOCATION = i.LOCATION inner join ITEM t on i.ITEM = t.ITEM
where
t.USER_DEF6 = '10'
and i.LOCATION = '000-gb-01'
group by
i.item,i.company
) t

Convert Exist condition to Join with T-SQL

I am trying to convert the following T-SQL Select query to exclude "Exists" Clause and Include "Join" Clause. but i am ending up not getting the right result. can some one from this expert team help me with some tips.
select *
FROM HRData
INNER JOIN (
SELECT eeceeid, MIN(eecdateoftermination) eTermDate
FROM dbo.empcomp
INNER JOIN
(
SELECT xeeid FROM HRData_EEList
INNER JOIN dbo.empcomp t ON xeeid = eeceeid AND xcoid = eeccoid
WHERE eecemplstatus = 'T' AND eectermreason <> 'TRO' AND eeccoid <> 'WAON6'
AND EXISTS ( SELECT 1 FROM dbo.empded
INNER JOIN dbo.dedcode on deddedcode = eeddedcode AND deddedtype = 'MED' AND (eedbenstopdate IS NULL OR eedbenstopdate > '12/31/2005')
WHERE eedeeid = xeeid AND eedcoid = xcoid )
GROUP BY xeeid
HAVING COUNT(*) > 1) Term ON xeeid = eeceeid
group by eeceeid
) Terms ON eeid = eeceeid AND Termdate = eTermDate
The algorithm to convert EXISTS to JOIN is very simple.
Instead of
FROM A
WHERE EXISTS (SELECT *
FROM B
WHERE A.Foo = B.Foo)
Use
FROM A
INNER JOIN (SELECT DISTINCT Foo
FROM B) AS B
ON A.Foo = B.Foo
But the first one probably will be optimised better
Interesting request.
select *
FROM HRData
INNER JOIN (
SELECT eeceeid, MIN(eecdateoftermination) eTermDate
FROM dbo.empcomp
INNER JOIN
(
SELECT xeeid FROM HRData_EEList
INNER JOIN dbo.empcomp t ON xeeid = eeceeid AND xcoid = eeccoid
INNER JOIN
( SELECT DISTINCT xeeid, xcoid FROM dbo.empded
INNER JOIN dbo.dedcode on deddedcode = eeddedcode AND deddedtype = 'MED' AND (eedbenstopdate IS NULL OR eedbenstopdate > '12/31/2005')
-- WHERE eedeeid = xeeid AND eedcoid = xcoid
) AS A ON xeeid = A.xeeid AND eedcoid = A.eedcoid
WHERE eecemplstatus = 'T' AND eectermreason <> 'TRO' AND eeccoid <> 'WAON6'
GROUP BY xeeid
HAVING COUNT(*) > 1) Term ON xeeid = eeceeid
group by eeceeid
) Terms ON eeid = eeceeid AND Termdate = eTermDate
Another method of converting an exists to a join is to use a ROW_NUMBER() in the subselect to assist in removing duplicates.
EXISTS:
FROM A
WHERE EXISTS (SELECT *
FROM B
WHERE B.Condition = 'true' AND A.Foo = B.Foo)
JOIN:
FROM A
JOIN (SELECT B.Foo, ROW_NUMBER() OVER (PARTITION BY B.Foo ORDER BY B.Foo) RN
FROM B
WHERE B.Condition = 'true') DT
ON A.Foo = DT.Foo AND DT.RN = 1
The ORDER BY is totally arbitrary since you don't care which record it selects, but it's required. You may be able to use (SELECT NULL) instead.

Using a group by to group a select statement

Using a group by to group a select stament
SELECT
k.Ivalue, k.JOBDESCRIPTION ,
count( k.Ivalue) as TOTAL
FROM
(SELECT
a."ID" as Ivalue, b."JOBDESCRIPTION", rq."CURRENTSTATUS"
FROM
tblG2o_Requests a
INNER JOIN
tblG2o_JOBS b ON a."JOBPOSTID" = b."ID"
INNER JOIN
(SELECT
r.REQUESTID, ir."CURRENTSTATUS"
FROM
TBLG2O_RESULTSPOOL r
INNER JOIN
tblG2o_Requests ir ON r.RequestID = ir."ID"
WHERE
r.ShortListed = '1') rq ON rq.REQUESTID = a."ID"
WHERE
"ACTIVE" = '1'
AND "DATECOMPLETED" IS NULL
ORDER BY
"REQUESTDATE" DESC) k
GROUP BY
k.JOBDESCRIPTION
What is the question? You seem to be missing the group by clause, and you do not need double quotes around field names unless you have spaces in them, and even then, if TSQL for example, you would use [] in preference.
I had to remove an ORDER BY in the subquery, that isn't allowed unless other conditions demand it (like TOP n in TSQL)
SELECT
k.Ivalue
, k.JOBDESCRIPTION
, COUNT(k.Ivalue) AS TOTAL
FROM (
SELECT
a.ID AS Ivalue
, b.JOBDESCRIPTION
, rq.CURRENTSTATUS
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a.JOBPOSTID = b.ID
INNER JOIN (
SELECT
r.REQUESTID
, ir.CURRENTSTATUS
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r.RequestID = ir.ID
WHERE r.ShortListed = '1'
) rqenter
ON rq.REQUESTID = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
) k
GROUP BY
k.Ivalue
, k.JOBDESCRIPTION
Finally worked
SELECT
k.Ivalue
, l.JOBDESCRIPTION
, k.TOTAL,
k.CURRENTSTATUS
FROM (
SELECT
a.ID AS Ivalue
,b.ID as JobPostID
, rq."CURRENTSTATUS"
,COUNT(a.ID) AS TOTAL
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a."JOBPOSTID" = b.ID
INNER JOIN (
SELECT
r."REQUESTID"
, ir."CURRENTSTATUS"
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r."REQUESTID" = ir.ID
WHERE r."SHORTLISTED" = 1
) rq
ON rq."REQUESTID" = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
GROUP BY
a.ID ,b.ID
, rq."CURRENTSTATUS" ) k
inner join tblG2o_JOBS l on k.JobPostID =l.ID
enter code here

How to convert correlated sub query containing duplicate table to non-correlated one?

I have to convert the correlated sub-query to non-correlated sub-query cuz of performance issues .
like that :
The correlated sub-query :(So slow ) returns 4000 row
SELECT a.personid,a.name,b.conid,d.condat,e.connam
FROM main_empr a INNER JOIN coninr b
ON a.personid = b.personid AND a.calc_year = b.calc_year
INNER JOIN mainconinr c
ON b.conid = c.conid
INNER JOIN coninr d
ON a.personid = d.personid AND a.calc_year = d.calc_year
INNER JOIN mainconinr e
ON d.conid = e.conid
WHERE c.active_flag = 1 and c.endreward_flag = 1
AND d.condat = (SELECT MIN(bb.condat) FROM coninr bb WHERE bb.personid = b.personid AND bb.calc_year = b.calc_year AND ((bb.conid > 0 AND bb.conid < 4 ) OR (bb.conid IN(16,6) )) )
AND b.condat = (SELECT MAX(bb.condat) FROM coninr bb WHERE bb.personid = b.personid AND bb.calc_year = b.calc_year AND ((bb.conid > 0 AND bb.conid < 4 ) OR (bb.conid IN(16,6) )) )
AND ( 0 = ( SELECT COUNT(*) FROM servmain x WHERE x.personid = a.personid AND x.calc_year = a.calc_year )
OR b.condat > ( SELECT MAX(x.serv_date) FROM servmain x WHERE x.personid = a.personid AND x.calc_year = a.calc_year ) )
AND a.calc_year = 2018
The non-correlated query :returns about 12300 rows!!
SELECT a.personid,a.name,b.conid,d.condat,e.connam
FROM main_empr a INNER JOIN
coninr b
ON a.personid = b.personid AND a.calc_year = b.calc_year
INNER JOIN mainconinr c
ON b.conid = c.conid
INNER JOIN coninr d
ON a.personid = d.personid AND a.calc_year = d.calc_year
INNER JOIN mainconinr e ON d.conid = e.conid
INNER JOIN
(SELECT MAX(bb.condat) AS condat ,bb.personid,bb.calc_year ,bb.conid
FROM coninr bb
GROUP BY bb.personid,bb.calc_year,bb.conid
)Max_cont
ON Max_cont.personid = b.personid AND Max_cont.calc_year = b.calc_year AND Max_cont.condat = b.condat AND ((Max_cont.conid > 0 AND Max_cont.conid < 4 ) OR (Max_cont.conid IN(16,6) ))
INNER JOIN
(SELECT MIN(dd.condat) AS condat ,dd.personid,dd.calc_year,dd.conid
FROM coninr dd GROUP BY dd.personid,dd.calc_year,dd.conid
)Min_cont
ON Min_cont.personid = d.personid AND Min_cont.calc_year = d.calc_year AND Min_cont.condat = d.condat AND ((Min_cont.conid > 0 AND Min_cont.conid < 4 ) OR (Min_cont.conid IN(16,6) ))
WHERE c.active_flag = 1 and c.endreward_flag = 1
AND ( 0 = ( SELECT COUNT(*) FROM servmain x WHERE x.personid = a.personid AND x.calc_year = a.calc_year )
OR b.condat > ( SELECT MAX(x.serv_date) FROM servmain x WHERE x.personid = a.personid AND x.calc_year = a.calc_year ) )
AND a.calc_year = 2018
The problem is :
I use the coninr table twice to get the last and the first contract date in the same row .
It works fine in the first query but it was so slow because of the correlated sub-query,but in the second query it brings more than one row for the same person one of them for the first contract date and the other for the last one !!
How to fix this problem ?
This looks reasonable, but I've no way to know how it'll perform:
SELECT a.personid,a.name,b.conid,d.condat,e.connam
FROM main_empr a INNER JOIN coninr b
ON a.personid = b.personid AND a.calc_year = b.calc_year
INNER JOIN mainconinr c
ON b.conid = c.conid
INNER JOIN coninr d
ON a.personid = d.personid AND a.calc_year = d.calc_year
INNER JOIN mainconinr e
ON d.conid = e.conid
inner join
(
SELECT bb.personid, bb.calc_year, bb.conid, MIN(bb.condat) MinDate, MAX(bb.condat) MaxDate
FROM coninr bb WHERE
where (bb.conid > 0 and bb.conid < 4) or (bb.conid in (6, 16))
group by bb.personid, bb.calc_year, bb.conid
) zz on d.concat = zz.MinDate and b.condat = zz.MaxDate and b.personid = zz.personid and b.calc_year = zz.calc_year
left outer join
(
select s.personid, s.calc_year, max(s.serv_date) MaxServDate
from servmain s
group by s.personid, s.calc_year
) s on a.personid = s.personid and a.calc_year = s.calc_year
WHERE c.active_flag = 1 and c.endreward_flag = 1
and (s.MaxServDate is null or b.condat ? s.MaxServDate
AND a.calc_year = 2018
You don't need two queries for table coninr, you can get min and max in the same query with the group by. Also, for ServMain, doing a left outer join and putting in the where that either it's null (equivalent to count(*) = 0) or is less than b.condat takes care of that.

mysql query to three tables, want to use JOIN instead subquery

I want to use join instead subquery to find the trade id not exist on trade_log filtered by ip and current date for mysql syntax below.
SELECT plug.id as a,
plug.url as b,
trade.id as c
FROM plug, trade
WHERE trade.id = plug.trade_id
AND trade.id NOT IN (SELECT trade_log.trade_id
FROM trade_log
WHERE trade_log.ip = '".$ip."'
AND trade_log.log_date = CURDATE())
AND trade.status = 1
AND plug.status = 1
ORDER BY plug.weight DESC
LIMIT 1
Please help me...
Use:
SELECT p.id as a,
p.url as b,
t.id as c
FROM PLUG p
JOIN TRADE t ON t.id = p.trade_id
AND t.status = 1
LEFT JOIN TRADE_LOG tl ON tl.trade_id = t.id
AND tl.ip = mysql_real_escape_string($ip)
AND tl.log_date = CURDATE()
WHERE p.status = 1
AND tl.ip IS NULL
ORDER BY p.weight DESC
LIMIT 1
Same as OMG Ponies:
SELECT p.id as a,
p.url as b,
t.id as c
FROM plug p
INNER JOIN trade t ON (t.id = p.trade_id AND t.status = 1)
LEFT JOIN trade_log l ON (l.trade_id = t.id AND l.ip = '".$ip."' AND l.log_date = CURDATE())
WHERE p.status = 1 AND l.trade_id IS NULL
ORDER BY p.weight DESC
LIMIT 1