Based on this table
key sampleID rs A1 A2
1 12345 rs123 C C
2 12345 rs345 C C
3 11110 rs123 C C
4 11110 rs345 C A
This statement
SELECT sampleID
FROM QS_base
WHERE (rs = 'rs123' AND A1 = 'C' AND A2 = 'C')
OR (rs = 'rs345' AND A1 = 'C' AND A2 = 'C')
Returns
12345
12345
11110
And this statement
SELECT sampleID
FROM QS_base
WHERE (rs = 'rs123' AND A1 = 'C' AND A2 = 'C')
AND (rs = 'rs345' AND A1 = 'C' AND A2 = 'C')
Returns no records. I expected it to return
12345
12345
Why is it retuning no results and is there a way to write it so that the above result can be obtained?
You can get what you want using group by and having:
SELECT sampleID
FROM QS_base
WHERE (rs = 'rs123' AND A1 = 'C' AND A2 = 'C') OR
(rs = 'rs345' AND A1 = 'C' AND A2 = 'C')
GROUP BY sampleID
HAVING COUNT(DISTINCT rs) = 2;
The AND will need both the condition to be satisfied at the same time and can not find a row with 2 different condition.
You can use exits to do it
select t1.sampleID
from QS_base t1
where
t1.rs = 'rs123' AND t1.A1 = 'C' AND t1.A2 = 'C'
and exists
(
select 1 from QS_base t2 where t1.sampleID = t2.sampleID
and t2.rs = 'rs345' AND t2.A1 = 'C' AND t2.A2 = 'C'
)
You're looking for samples where rs is both 'rs123' and 'rs345'. The query only looks at rows individually.
You have excluding conditions in the second example. The where clause:
WHERE (rs = 'rs123' AND A1 = 'C' AND A2 = 'C') AND (rs = 'rs345' AND A1 = 'C' AND A2 = 'C')
cloud be written as:
WHERE rs = 'rs123' AND rs = 'rs345' AND A1 = 'C' AND A2 = 'C'
rs cannot be equal to rs123 and rs345 at the sime time. :)
As for the second part of Your question, yes it certainly can return result that You need. Just write:
WHERE (rs = 'rs123' AND A1 = 'C' AND A2 = 'C')
I assume You have additional requirements on this query, if so, please state them in You post.
Related
Im having and issue where in my table FarmerGroups I have multiple records by BSI_Code and I am getting double results for GallonsIssued due to this inner join. Is there a way to get the unique value of GallonsIssued or a way to just get results by individual BSI_CODE
With Summary as (
Select B_NAME as Branch, LOC as Location
,SUM(payment) as Gallons
,SUM(case when printed = 1 THEN Fee ELSE NULL END) as FeeCollected
,SUM(case when printed = 0 THEN Fee ELSE NULL END) as FeeNotCollected
,SUM(case when printed = 1 THEN Payment ELSE NULL END) as GallonsIssued
,SUM(case when printed = 0 THEN Payment ELSE NULL END) as GallonsNotIssued
From SicbWeeklyDeliveriesFuel F Inner Join FarmerGroups G ON G.BSI_CODE = F.BSI_CODE AND G.CROP_SEASON = F.CROP_SEASON AND F.B_NAME = G.BRANCH
Where F.CROP_SEASON = #cropseason
Group By B_NAME, LOC
)
SELECT Branch
,Location
,Gallons
,GallonsIssued
,GallonsNotIssued
,FeeCollected
,FeeNotCollected
,((GallonsIssued/Gallons) * 100) as pct_GallonsCollected
FROM Summary
Order by Location, Branch
For SicbWeeklyDeliveriesFuel
BSI_CODE
Payment
LOC
CROP_SEASON
Fee
B_NAME
FNAME
66
125
CZ
5
12.5
DOUGLAS
John K
55
147
OW
5
14.7
CALEDONIA
Tim H
66
95
CZ
5
9.5
DOUGLAS
John K
For Farmer Groups
BSI_CODE
Farmer
CROP_SEASON
BRANCH
TEST_GROUP
66
John K
5
DOUGLAS
1A
55
Tim H
5
CALEDONIA
1B
66
John K
5
DOUGLAS
2A
Your selection for the JOIN of G.BSI_CODE = F.BSI_CODE AND G.CROP_SEASON = F.CROP_SEASON AND F.B_NAME = G.BRANCH does not uniquely define the rows.
You will need to also include F..FNAME = G.Farmer otherwise the first row of SicbWeeklyDeliveriesFuel (BSI_CODE = 66, CROP_SEASON = 5 and B_NAME = DOUGLAS) matches both the first and last rows of FarmerGroups. Likewise the third row also matches the same two rows in FarmerGroups.
The reason for the duplication is the field TEST_GROUP in FarmerGroups Table.
But you don't need this field in the Join.
First,a CTE to get the info you need in the join without duplicates.
then your old join to the new CTE.
Try this:
WITH FarmersGroup AS
(
SELECT DISTINCT
BSI_CODE
, CROP_SEASON
, BRANCH
FROM FarmerGroups
)
, Summary AS
(
SELECT
Branch = B_NAME
, Location = LOC
, Gallons = SUM(payment)
, FeeCollected = SUM(case when printed = 1 THEN Fee ELSE NULL END)
, FeeNotCollected = SUM(case when printed = 0 THEN Fee ELSE NULL END)
, GallonsIssued = SUM(case when printed = 1 THEN Payment ELSE NULL END)
, GallonsNotIssued = SUM(case when printed = 0 THEN Payment ELSE NULL END)
FROM SicbWeeklyDeliveriesFuel F
JOIN FarmerGroup G ON G.BSI_CODE = F.BSI_CODE
AND G.CROP_SEASON = F.CROP_SEASON
AND G.BRANCH = F.B_NAME
WHERE F.CROP_SEASON = #cropseason
GROUP BY
B_NAME, LOC
)
SELECT
Branch
, Location
, Gallons
, GallonsIssued
, GallonsNotIssued
, FeeCollected
, FeeNotCollected
, pct_GallonsCollected = ((GallonsIssued/Gallons) * 100)
FROM Summary
ORDER BY
Location
, Branch
You can use Andy's code above and it should do the job or you can just replace the table join in your current query
Change the following
Inner Join FarmerGroups G ON G.BSI_CODE = F.BSI_CODE AND G.CROP_SEASON = F.CROP_SEASON AND F.B_NAME = G.BRANCH
to
Inner join (select SELECT DISTINCT
BSI_CODE
, CROP_SEASON
, BRANCH
FROM FarmerGroups ) G on
ON G.BSI_CODE = F.BSI_CODE AND G.CROP_SEASON = F.CROP_SEASON AND F.B_NAME = G.BRANCH
I want to fetch that SQL rows:
SELECT aa.*
FROM Answers AS aa
WHERE event_id = 1 AND
( (aa.form_item_id = 1 AND form_item_reply = "John") AND
(aa.form_item_id = 2 AND form_item_reply = "Doe")
)
ORDER BY aa.id DESC
But it's given wrong result, I want to fetch that (aa.form_item_id = 1 AND form_item_reply = "John") and (aa.form_item_id = 2 AND form_item_reply = "Doe").
It have to give me above 2 condition result.
You can use OR
SELECT aa.* FROM Answers AS aa WHERE event_id = 1 AND
(
(aa.form_item_id = 1 AND form_item_reply = "John")
OR (aa.form_item_id = 2 AND form_item_reply = "Doe")
) ORDER BY aa.id DESC
Perhaps you just want OR:
SELECT aa.*
FROM Answers AS aa
WHERE event_id = 1 AND
( (aa.form_item_id = 1 AND form_item_reply = 'John') OR
(aa.form_item_id = 2 AND form_item_reply = 'Doe')
)
ORDER BY aa.id DESC
I have a requirement to get the result from the first matched condition and if it finds result in that level then return from there or go to Next level to
find the result .
Any help appreciated.
This is a prioritization query (with ties). One method uses dense_rank():
select rsc.*
from (select rsc.*,
dense_rank() over (order by case when rsc.entityId = :accountId and rsc.entityTypeCode = 'A' then 1
when rsc.entityId = :companyId and rsc.entityTypeCode = 'C' then 2
when rsc.entityId = :issuerId and rsc.entityTypeCode = 'I' then 3
else 4
end) as seqnum
from CurrentRuleSetContents rsc
where (rsc.entityId = :accountId and rsc.entityTypeCode = 'A') or
(rsc.entityId = :companyId and rsc.entityTypeCode = 'C') or
(rsc.entityId = :issuerId and rsc.entityTypeCode = 'I') or
(rsc.industryCode = :industryCode)
) rsc
where seqnum = 1;
If there are three tables, TableItem, TableAbcd and TablePqrs, as below
TableItem
ID item
1 item1
TableAbcd
ID Item ColA ColB ColC ColD
1 item1 A1 B1 C1 D1
TablePqrs
ID item ColA ColB ColC ColD ColValue
1 item1 A1 B1 null null 10000
2 item1 A1 B1 C1 D1 100
Here, for a given Item, There has to be just one record in the output which has the maximum columns matching in TableAbcd and TablePqrs.
Since row 1 of TableAbcd has maximum matching columns with TablePqrs row 2.
My output for join with above three tables should be,
item ColA ColB ColC ColD ColValue
item1 A1 B1 C1 D1 100
Code tried so far,
Select item, ColA, ColB, ColC, ColD, ColValue
FROM TableItem a
LEFT OUTER JOIN TableAbcd b
ON a.item = b.item
LEFT OUTER JOIN TablePqrs c
ON (b.ColA = c.ColA AND b.ColB = c.ColB AND b.ColC = c.ColC AND b.ColD = c.ColD)
OR (b.ColA = c.ColA AND b.ColB = c.ColB AND b.ColC = c.ColC)
OR (b.ColA = c.ColA AND b.ColB = c.ColB)
if fetch's me two records, i know there may be design issues, but we are getting data from third party legacy system, which has table structure as per its needs and sending this to another interface.
Please suggest.
Here the question is: How many columns match between B and C?
For the join clause you only need that at least one column of b matches the same column in c:
from c
left join b
on c.A = b.A or c.B = b.B or c.C = b.C or c.D = b.D
You can calc it by:
(case when c.A = b.A then 1 else 0 end)
+ (case when c.B = b.B then 1 else 0 end)
+ (case when c.C = b.B then 1 else 0 end)
+ (case when c.D = b.D then 1 else 0 end) as matches
Then simply order by matching rows (descendant) and limit the result to 1 row.
select
c.id, c.item, c.A, c.B, c.C, c.D, c.colValue,
(case when c.A = b.A then 1 else 0 end)
+ (case when c.B = b.B then 1 else 0 end)
+ (case when c.C = b.B then 1 else 0 end)
+ (case when c.D = b.D then 1 else 0 end) as matches
from c
left join b
on c.A = b.A or c.B = b.B or c.C = b.C or c.D = b.D
order by
((case when c.A = b.A then 1 else 0 end)
+ (case when c.B = b.B then 1 else 0 end)
+ (case when c.C = b.B then 1 else 0 end)
+ (case when c.D = b.D then 1 else 0 end)) desc
limit 1;
I've set up a rextester example just to check it: http://rextester.com/IPA67860
With TableAbcd called a and TablePqrs called p, the number of matches is (p.cola = a.cola) + (p.colb = a.colb) + (p.colc = a.colc) + (p.cold = a.cold), because in MySQL true is 1 and false is 0.
Now you are looking for the p records for which no other p record exists with a higher number of matches:
select *
from tablepqrs p1
where not exists
(
select *
from tablepqrs p2
join tableabcd a on a.item = p2.item
where p2.item = p1.item
and (p2.cola = a.cola) + (p2.colb = a.colb) + (p2.colc = a.colc) + (p2.cold = a.cold) >
(p1.cola = a.cola) + (p1.colb = a.colb) + (p1.colc = a.colc) + (p1.cold = a.cold)
);
In the code below you can see another option to filter. Its a similar approach to the one proposed by McNets, but using window functions.
The key is to compute a ranking which allows to determine the TablePqrs row with the best match. In the other hand, if two rows have the same ranking for the same item value, we have to use additional criteria to undo the tie. in the example, the criteria is the ID of the TableAbcd table. I'm not using outer joins so there will be no results for TableItems records without match ranking.
I'm not pretty sure if it really fits what you really want, just try it and get your own conclusions.
SELECT TableItem.id,
TableItem.item,
TablePqrs.colA,
TablePqrs.colB,
TablePqrs.colC,
TablePqrs.colD,
TablePqrs.value
FROM TableItem
INNER JOIN (SELECT DISTINCT
tableItemId,
FIRST_VALUE(tablePqrsId) OVER (PARTITION BY tableItemId ORDER BY ranking DESC, tablePqrsId DESC) tablePqrsId
FROM (SELECT rankTableItem.ID tableItemId,
rankTablePqrs.ID tablePqrsId,
CASE WHEN rankTablePqrs.colA IS NULL THEN 0 ELSE 1 END +
CASE WHEN rankTablePqrs.colB IS NULL THEN 0 ELSE 1 END +
CASE WHEN rankTablePqrs.colC IS NULL THEN 0 ELSE 1 END +
CASE WHEN rankTablePqrs.colD IS NULL THEN 0 ELSE 1 END ranking
FROM TableItem rankTableItem
INNER JOIN TableAbcd rankTableAbcd ON rankTableItem.item = rankTableAbcd.item
INNER JOIN TablePqrs rankTablePqrs ON rankTablePqrs.item = rankTableAbcd.item
AND (rankTableAbcd.colA = rankTablePqrs.colA
OR rankTableAbcd.colB = rankTablePqrs.colB
OR rankTableAbcd.colC = rankTablePqrs.colC
OR rankTableAbcd.colD = rankTablePqrs.colD))) pivotTable ON pivotTable.tableItemId = TableItem.Id
INNER JOIN TablePqrs ON TablePqrs.Id = pivotTable.tablePqrsId
I tried the below thing and it worked, the coalesce helps me prioritise which value to pick depending upon the order i mention in it.
Select item, ColA, ColB, ColC, ColD, ColValue
FROM TableItem a
LEFT OUTER JOIN (
SELECT item,
COALESCE(c1.ColValue,c2.ColValue,c3.ColValue) ColValue
FROM abc b
LEFT OUTER JOIN pqr c1
ON b.ColA = c1.ColA AND b.ColB = c1.ColB AND b.ColC = c1.ColC AND b.ColD = c1.ColD
LEFT OUTER JOIN pqr c2
ON b.ColA = c2.ColA AND b.ColB = c2.ColB AND b.ColC = c2.ColC
LEFT OUTER JOIN pqr c3
ON b.ColA = c3.ColA AND b.ColB = c3.ColB
GROUP BY item
) as Fact
ON Fact.item = a.item
I am looking for help with an advanced MySQL query. My current query, shown below, works fine. I would like to add an additional field, so I don't have to create a separate query. The new field, count(TableA.Field05), should result in the total number of records from TableA.
TableA has 10 records
TableB has 100 records
SELECT count(TableB.Answer) AS unAnswered
FROM TableA
LEFT JOIN TableB
ON ( TableA.Field01 = TableB.fkField01 AND TableA.Field02 = TableB.fkField02 AND TableB.Answer = '1')
WHERE TableB.fkField03 IS NULL AND TableA.Field04 = 10
GROUP BY TableA.Field01, TableA.Field02
Result:
unAnswered = 8 this is correct
The desired result is:
unAnswered = 8
count(TableA.Field05) = 10
--
This is an example of the data and results.
SELECT count(TableB.Answer) AS unAnswered
FROM TableA LEFT JOIN TableB ON ( TableA.Field01 = TableB.fkField01 AND TableA.Field02 = TableB.fkField02 AND TableB.Answer = '1')
WHERE TableB.fkField03 IS NULL AND TableA.Field04 = 10
GROUP BY TableA.Field01, TableA.Field02
TableA
Field01 = 1, Field02 = 1, Field03 = 10
Field01 = 1, Field02 = 2, Field03 = 21
Field01 = 1, Field02 = 3, Field03 = 22
Field01 = 1, Field02 = 4, Field03 = 34
TableB
Field01 = 1, Field02 = 1, Answer = 1
Field01 = 1, Field02 = 2, Answer = 1
Field01 = 1, Field02 = 3, Answer = 1
Field01 = 2, Field02 = 1, Answer = 1
Field01 = 2, Field02 = 2, Answer = 1
Field01 = 2, Field02 = 3, Answer = 1
Result
count(TableB.Answer) AS unAnswered = 1
Result trying to achive
count(TableB.Answer) AS unAnswered = 1
count(TableA.Field03) = 4
Any help will be greatly appreciated.
If you are just looking to add the count of tableA to your current query just add it to your select statement:
'SELECT count(TableB.Answer) AS unAnswered, count(TableA.Field02) FROM TableA ...'
I just figured out my own question.
SELECT **COALESCE(count(DISTINCT TableB.Answer)) AS unAnswered, count(DISTINCT TableA.Field05)**
FROM TableA
LEFT JOIN TableB
ON ( TableA.Field01 = TableB.fkField01 AND TableA.Field02 = TableB.fkField02 AND TableB.Answer = '1')
WHERE TableB.fkField03 IS NULL AND TableA.Field04 = 10
GROUP BY TableA.Field01, TableA.Field02
Adding COALESCE and DISTINCT solved my issue. Thank you everyone for your help.