sql confusion with ANDs - sql

I am having a bit of confusion with SQL querying using ANDs.
the query is as follows:
SELECT count(cdr.id) as callTotal,
sum(cdr.callDurationSeconds) as timeTotal,
users.firstname,
users.surname,
MAX(cdr.callDuration) as maxCallDuration,
AVG(cdr.answeredTime) as avgAnswerTime,
AVG(cdr.callDurationSeconds) as avgTimeTotal,
cdr.userId,
COUNT(IF(cdr.callDurationSeconds > '0', 1, NULL)) AS answeredCalls
FROM cdr
LEFT JOIN users ON cdr.userId = users.id
WHERE cdr.company = 'C47B0BCCDCE92F'
AND cdr.dateCreated LIKE '2012-11-02%'
AND cdr.userId = 'U4BC3128209B01'
OR cdr.userId = 'U4A9FCCD73C6BB'
GROUP BY userId ORDER BY users.surname ASC ;
I want to query by the date on the second to last line, but then I wish to retrieve items with any of the posted cdr.userIds.
However it seems to disregard the date in this instance. I need the date to be non-optional and retrieve any data with the select Ids on the chosen date.

If you don't wanna play with OR / AND operators precedence in SQL (which is a rather bad idea), just add brackets.
AND (cdr.userId = 'U4BC3128209B01' OR cdr.userId = 'U4A9FCCD73C6BB')
or as pointed by Martin Smith, in your case, use an IN
AND cdr.userId IN ('U4BC3128209B01','U4A9FCCD73C6BB')

If I understand you correctly you want to select the items with that date AND have a specific id?
SELECT count(cdr.id) as callTotal,
sum(cdr.callDurationSeconds) as timeTotal,
users.firstname,
users.surname,
MAX(cdr.callDuration) as maxCallDuration,
AVG(cdr.answeredTime) as avgAnswerTime,
AVG(cdr.callDurationSeconds) as avgTimeTotal,
cdr.userId,
COUNT(IF(cdr.callDurationSeconds > '0', 1, NULL)) AS answeredCalls
FROM cdr
LEFT JOIN users ON cdr.userId = users.id
WHERE cdr.company = 'C47B0BCCDCE92F'
AND cdr.dateCreated LIKE '2012-11-02%'
AND cdr.userId IN('U4BC3128209B01','U4A9FCCD73C6BB')
GROUP BY userId ORDER BY users.surname ASC ;

You could wrap the OR with parenthesis like the others mentioned or use IN like this
SELECT count(cdr.id) as callTotal,
sum(cdr.callDurationSeconds) as timeTotal,
users.firstname,
users.surname,
MAX(cdr.callDuration) as maxCallDuration,
AVG(cdr.answeredTime) as avgAnswerTime,
AVG(cdr.callDurationSeconds) as avgTimeTotal,
cdr.userId,
COUNT(IF(cdr.callDurationSeconds > '0', 1, NULL)) AS answeredCalls
FROM cdr
LEFT JOIN users ON cdr.userId = users.id
WHERE cdr.company = 'C47B0BCCDCE92F'
AND cdr.dateCreated LIKE '2012-11-02%'
AND cdr.userId IN ('U4BC3128209B01','U4A9FCCD73C6BB') GROUP BY userId ORDER BY users.surname ASC ;
That way there's no OR, so no confusion

In SQL AND has a higher order then OR so by default your where resolves to
WHERE (cdr.company = 'C47B0BCCDCE92F'
AND cdr.dateCreated LIKE '2012-11-02%'
AND cdr.userId = 'U4BC3128209B01') OR cdr.userId = 'U4A9FCCD73C6BB'
Where you want
WHERE cdr.company = 'C47B0BCCDCE92F'
AND cdr.dateCreated LIKE '2012-11-02%'
AND (cdr.userId = 'U4BC3128209B01' OR cdr.userId = 'U4A9FCCD73C6BB')
Use brackets and it will clear things up.

Related

Single Query To Select Based On Parameters If Or not supplied

I have used SqlDataSource and have a select query based on District & Zone as below
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director') AND ((convert(varchar,a.districtid) LIKE '%2%') AND (convert(varchar,a.zoneid) LIKE '%25%')) ORDER BY a.[committee_id] DESC
It's an inline query. I have tried above query but not able to figure out how to Select condition based.
I want if district supplied then Select according to District, if both District & Zone supplied then Select according to both & If nothing supplied then Select All. But should be in single query. How should I do this?
First, fix your query so you are not using meaningless table aliases. Use table abbreviations! I would also drop all the square braces; they just make the query harder to write and to read.
Basically, you want comparisons with NULL in the WHERE clause. I have no idea why your sample code uses LIKE, particularly columns that appear to be numbers. Nothing in the question explains why LIKE is used for the comparison, so the idea is:
SELECT cd.committee_id as memberid, cd.membername,
cd.memberemail, cd.memberdesignation, cd.membercreatedby,
dm.districtname AS district, dm.districtid,
zm.zone_name AS zone, zm.zoneid
FROM committee_details cd LEFT JOIN
district_master dm
ON cd.districtid = dm.districtid LEFT JOIN
zone_master zm
ON zm.districtid = cd.districtid AND
zm.zoneid = cd.zoneid
WHERE cd.membercreatedby = 'director') AND
(cd.districtid = #district or #district is null) AND
(cd.zoneid = #zone or #zone is null)
ORDER BY cd.[committee_id] DESC;
If you were using LIKE, then I would phrase the logic like:
WHERE cd.membercreatedby = 'director') AND
(cast(cd.districtid as varchar(255)) like #district) AND
(cast(cd.zoneid as varchar(255)) like #zone)
And pass in the patterns as '%' when you want all values to match. This assumes that the columns in cd are not NULL. If they can be NULL, then you want an explicit comparison, as in the first example.
If I got the question right then you can use parameters and compare to the column itself if the values are not supplied or not present.
try the following:
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director')
AND b.districtname = isnull(nullif(#districtname, ''), b.districtname)
AND c.zone_name = isnull(nullif(#zone_name, ''), c.zone_name)
ORDER BY a.[committee_id] DESC

Select closest date to another date

I'm querying a table (COURSEPLACE) to generate a result set of students. This contains a range of variables taken from the course table.
I then want to join an Addresses table (which contains multiple address records per student) but only append to the results the 1 postcode that was created on the same (or the closest) date to the date that the Student record was created.
What I've tried is the following, but this only gets me those records where the date value is an exact match - how do I extend this to (effectively) find and select the postcode value from the address record that has the closest date stamp to the student record date stamp?:
SELECT cp.CONTACTNO, cp.AGEONENTRY, cp.COURSETITLE, cp.FACULTY, ad.POSTCODE
FROM COURSEPLACE cp
LEFT OUTER JOIN ADDRESS ad ON ad.CONTACTNO=cp.CONTACTNO
WHERE
cp.TYPE = 'Application'
AND cp.TERM = '2015/6'
AND
(
ad.TYPE = 'Home' AND CONVERT(VARCHAR(23),ad.CREATIONDATE,103) = CONVERT(VARCHAR(23),cp.CREATIONDATE,103)
)
SELECT TOP 1
cp.CONTACTNO, cp.AGEONENTRY, cp.COURSETITLE, cp.FACULTY, ad.POSTCODE,
FROM
COURSEPLACE cp
INNER JOIN ADDRESS ad ON ad.CONTACTNO=cp.CONTACTNO
WHERE CP.TYPE = 'Application'
AND CP.TERM = '2016/5'
AND AD.TYPE = 'Home'
ORDER BY
DATEDIFF(AD.CREATIONDATE, CP.CREATIONDATE) ASC;
Solved it with OUTER APPLY, given as an answer to a previous question:
OUTER APPLY (SELECT TOP 1 * FROM ADDRESS ad2 WHERE ad2.CONTACTNO=cp.CONTACTNO ORDER BY DATEDIFF(dd,cp.CREATIONDATE,ad2.CREATIONDATE)) AD
Give this a whirl....
SELECT cp.CONTACTNO, cp.AGEONENTRY, cp.COURSETITLE, cp.FACULTY, ad.POSTCODE
FROM COURSEPLACE cp
LEFT JOIN ADDRESS ad ON
ad.CONTACTNO=cp.CONTACTNO
INNER JOIN
(SELECT CONTACTNO, MAX(CREATIONDATE) dt
FROM ADDRESS
WHERE CREATIONDATE <= cp.CREATIONDATE
GROUP BY CONTACTNO) ad2 on ad2.dt = ad.CREATIONDATE and ad2.CONTACTNO = ad.CONTACTNO
WHERE
cp.TYPE = 'Application'
AND cp.TERM = '2015/6'

Not a group by expression Beginner

Here I have three tables
PLAYS {ID_athlete, ID_sport, best_result}
PARTICIPATE {ID_athlete, ID_competition, result}
ISAT {ID_sport, ID_competition}
I would like to update the best_result attribute IN PLAYS.
I wrote this but I have the "not a group expression" error.
UPDATE PLAYS PL
SET BEST_RESULT =
(
SELECT MAX(RESULT)
FROM PARTICIPATE P
GROUP BY P.ID_ATHLETE, P.ID_COMPETITION
HAVING PL.ID_ATHLETE = P.ID_ATHLETE
AND P.ID_COMPETITION IN
(
SELECT ID_COMPETITION
FROM ISAT
WHERE ID_SPORT = PL.ID_SPORT
)
)
I don't know where my error comes from. I want to get the max result of a certain athlete in a certain sport and put it in best_result.
I think you are looking for this. Use a where clause to limit it and take the max. HAVING is for aggregate filters.
UPDATE PLAYS PL
SET BEST_RESULT =
(
SELECT MAX(RESULT)
FROM PARTICIPATE P
WHERE PL.ID_ATHLETE = P.ID_ATHLETE
AND P.ID_COMPETITION IN
(
SELECT ID_COMPETITION
FROM ISAT
WHERE ID_SPORT = PL.ID_SPORT
)
)
You have got your WHERE and HAVING caluses mixed up. For this SQL (getting the max result), you don't even need GROUP BY or HAVING. Just plain a condition should do the job.
UPDATE PLAYS PL
SET BEST_RESULT =
(
SELECT MAX(RESULT)
FROM PARTICIPATE P
WHERE PL.ID_ATHLETE = P.ID_ATHLETE
AND P.ID_COMPETITION IN
(SELECT ID_COMPETITION
FROM ISAT
WHERE ID_SPORT = PL.ID_SPORT)
)

SQL get chat query

I have this query in sql, and i can't get it right.
I'm trying to make a query to get the results from chat.
select message, first_name, last_name, dataPost,picture
from chat_comms
right join utilizadores
on (chat_comms.id_writer = utilizadores.id_user)
or (chat_comms.id_reader = utilizadores.id_user)
where id_writer = 1
or (id_reader = 1 and id_writer = 13)
order by dataPost ASC
RESULT
the first_name, last_name, picture, should be different because they are different users, how can i solve this?
SQL FIDDLE:
VIEW SQL FIDDLE
It looks like you have the duplicate rows because one of the users is the "writer" and the other is the "reader". I'm guessing that you actually want one row for each row in chat_comms linked to both the "writer" and "reader". In this case you need to join to utilizadores twice instead of using the or:
select message, writer.first_name, writer.last_name, dataPost, picture
from chat_comms
left join utilizadores writer on chat_comms.id_writer = writer.id_user
left join utilizadores reader on chat_comms.id_reader = reader.id_user
where id_writer = 1
or (id_reader = 1 and id_writer = 13)
order by dataPost ASC
This is just a guess because you haven't adequately described the result you're trying to achieve.
please verify below mentioned query:
SELECT message, first_name, last_name, dataPost,picture
FROM chat_comms
RIGHT JOIN utilizadores
ON chat_comms.id_writer = utilizadores.id_user
OR (chat_comms.id_reader = utilizadores.id_user)
WHERE id_writer = 1
order by dataPost ASC
Hope that helps, thanks.

Column is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause

Ok here's my View (vw_LiftEquip)
SELECT dbo.tbl_equip_swl_unit.unit_id,
dbo.tbl_equip_swl_unit.unit_name,
dbo.tbl_equip_swl_unit.archived,
dbo.tbl_categories.category_id,
dbo.tbl_categories.categoryName,
dbo.tbl_categories.parentCategory,
dbo.tbl_categories.sub_category,
dbo.tbl_categories.desc_category,
dbo.tbl_categories.description,
dbo.tbl_categories.miscellaneous,
dbo.tbl_categories.category_archived,
dbo.tbl_equip_swl_unit.unit_name AS Expr1,
dbo.tbl_categories.categoryName AS Expr2,
dbo.tbl_categories.description AS Expr3,
dbo.tbl_equip_depts.dept_name,
dbo.tbl_equip_man.man_name,
dbo.tbl_Lifting_Gear.e_defects AS Expr7,
dbo.tbl_Lifting_Gear.e_defects_desc AS Expr8,
dbo.tbl_Lifting_Gear.e_defects_date AS Expr9,
dbo.tbl_equipment.equipment_id,
dbo.tbl_equipment.e_contract_no,
dbo.tbl_equipment.slID,
dbo.tbl_equipment.e_entered_by,
dbo.tbl_equipment.e_serial,
dbo.tbl_equipment.e_model,
dbo.tbl_equipment.e_description,
dbo.tbl_equipment.e_location_id,
dbo.tbl_equipment.e_owner_id,
dbo.tbl_equipment.e_department_id,
dbo.tbl_equipment.e_manafacture_id,
dbo.tbl_equipment.e_manDate1,
dbo.tbl_equipment.e_manDate2,
dbo.tbl_equipment.e_manDate3,
dbo.tbl_equipment.e_dimensions,
dbo.tbl_equipment.e_test_no,
dbo.tbl_equipment.e_firstDate1,
dbo.tbl_equipment.e_firstDate2,
dbo.tbl_equipment.e_firstDate3,
dbo.tbl_equipment.e_prevDate1,
dbo.tbl_equipment.e_prevDate2,
dbo.tbl_equipment.e_prevDate3,
dbo.tbl_equipment.e_insp_frequency,
dbo.tbl_equipment.e_swl,
dbo.tbl_equipment.e_swl_unit_id,
dbo.tbl_equipment.e_swl_notes,
dbo.tbl_equipment.e_cat_id,
dbo.tbl_equipment.e_sub_id,
dbo.tbl_equipment.e_parent_id,
dbo.tbl_equipment.e_last_inspector,
dbo.tbl_equipment.e_last_company,
dbo.tbl_equipment.e_deleted AS Expr11,
dbo.tbl_equipment.e_deleted_desc AS Expr12,
dbo.tbl_equipment.e_deleted_date AS Expr13,
dbo.tbl_equipment.e_deleted_insp AS Expr14,
dbo.tbl_Lifting_Gear.e_defects_action AS Expr15,
dbo.tbl_equipment.e_rig_location,
dbo.tbl_Lifting_Gear.e_add_type AS Expr17,
dbo.tbl_Lifting_Gear.con_id,
dbo.tbl_Lifting_Gear.lifting_date,
dbo.tbl_Lifting_Gear.lifting_ref_no,
dbo.tbl_Lifting_Gear.e_id,
dbo.tbl_Lifting_Gear.inspector_id,
dbo.tbl_Lifting_Gear.lift_testCert,
dbo.tbl_Lifting_Gear.lift_rig_location,
dbo.tbl_Lifting_Gear.inspected,
dbo.tbl_Lifting_Gear.lifting_through,
dbo.tbl_Lifting_Gear.liftingNDT,
dbo.tbl_Lifting_Gear.liftingTest,
dbo.tbl_Lifting_Gear.e_defects,
dbo.tbl_Lifting_Gear.e_defects_desc,
dbo.tbl_Lifting_Gear.e_defects_date,
dbo.tbl_Lifting_Gear.e_defects_action,
dbo.tbl_Lifting_Gear.lift_department_id,
dbo.tbl_Lifting_Gear.lifting_loc
FROM dbo.tbl_equipment
INNER JOIN dbo.tbl_equip_swl_unit
ON dbo.tbl_equipment.e_swl_unit_id = dbo.tbl_equip_swl_unit.unit_id
INNER JOIN dbo.tbl_categories
ON dbo.tbl_equipment.e_cat_id = dbo.tbl_categories.category_id
INNER JOIN dbo.tbl_equip_depts
ON dbo.tbl_equipment.e_department_id = dbo.tbl_equip_depts.dept_id
INNER JOIN dbo.tbl_equip_man
ON dbo.tbl_equipment.e_manafacture_id = dbo.tbl_equip_man.man_id
INNER JOIN dbo.vwSubCategory
ON dbo.tbl_equipment.e_sub_id = dbo.vwSubCategory.category_id
INNER JOIN dbo.vwDescCategory
ON dbo.tbl_equipment.e_cat_id = dbo.vwDescCategory.category_id
INNER JOIN dbo.tbl_Lifting_Gear
ON dbo.tbl_equipment.equipment_id = dbo.tbl_Lifting_Gear.e_id
And here's the select statement with subquery that I am using:
SELECT *
FROM vw_LiftEquip
WHERE lifting_loc = ? AND
con_id = ? AND
EXPR11 =
'N'(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
)
ORDER BY lifting_ref_no,
category_id,
e_swl,
e_serial
I get the error :
Column "vw_LiftEquip.category_id" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Can't see why its returning that error, this is admittedly the first time I've ran a subquery on such a complex view, and I am a bit lost, thanks in advance for any help. I have looked through the similar posts and can find no answers to this one, sorry if I am just being dumb.
You are missing AND between EXPR11 = 'N' and (SELECT MAX(...
Otherwise, it looks OK. MAX without GROUP BY is allowed if you have no other columns in the SELECT
Update: #hvd also noted that you have nothing to compare to MAX(lifting_date). See comment
Update 2,
SELECT *
FROM vw_LiftEquip v1
CROSS JOIN
(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
) v2
WHERE v1.lifting_loc = ? AND
v1.con_id = ? AND
v1.EXPR11 = 'N'
ORDER BY v1.lifting_ref_no,
v1.category_id,
v1.e_swl,
v1.e_serial