I have a table 'A' that look like that :
L
S
A
1
B
1
C
0
D
1
And I want to add a new column U saying 'OK' or 'NOK' depending on following condition :
If A = 0 & B = 1 => Line A = NOK Else OK
If A = 1 & C = 1 => Line B = NOK Else OK
If B = 1 & D = 1 => Line C = NOK Else OK
So it should look like :
L
S
U
A
1
OK
B
1
OK
C
0
NOK
D
1
OK
I have tried with a CASE, but it is not working, I cannot do the "then C = NOK" when I'm in "If B"
SELECT A.*,
(
CASE
WHEN (L = 'A' AND S = 0) AND (L = 'B' AND S = 1) THEN "NOK"
WHEN (L = 'A' AND S = 1) AND (L = 'C' AND S = 1) THEN "NOK"
WHEN (L = 'B' AND S = 1) AND (L = 'D' AND S = 1) THEN "NOK"
ELSE 'OK'
END
) AS `U`
FROM A
How can I achieve that in mysql directly ? Is it possible ?
Thanks
Related
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
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.
In the UPDATE statement below, the InspectionChg, MileageChg, FuelChg and FreightChg columns are not updating to temp table. Goal is to aggregate charges. I have tried several variations and I cannot get Temp Table Columns to update.
UPDATE #TTable
SET ChargeCode = id.cht_itemcode,
InspectionChg = CASE WHEN LEFT(id.cht_itemcode, 3) = 'INS' THEN
InspectionChg+id.ivd_charge ELSE InspectionChg+0 END,
MileageChg = CASE WHEN LEFT(id.cht_itemcode, 4) = 'MILE' THEN MileageChg+id.ivd_charge
ELSE MileageChg+0 END,
FuelChg = CASE WHEN LEFT(id.cht_itemcode, 4) = 'FUEL' THEN
FuelChg+id.ivd_charge ELSE FuelChg+0 END,
FreightChg = CASE WHEN LEFT(id.cht_itemcode, 2) = 'LH' THEN FreightChg+id.ivd_charge
ELSE FreightChg+0 END,
Rate = 1
FROM #TTable
INNER JOIN invoicedetail as id
on #TTable.OrderNumber = id.Ord_hdrnumber
What is wrong?
UPDATE TT
SET TT.ChargeCode = id.cht_itemcode ,
TT.InspectionChg = ( CASE WHEN LEFT(id.cht_itemcode, 3) = 'INS'
THEN InspectionChg + id.ivd_charge
ELSE InspectionChg + 0
END ) ,
TT.MileageChg = ( CASE WHEN LEFT(id.cht_itemcode, 4) = 'MILE'
THEN MileageChg + id.ivd_charge
ELSE MileageChg + 0
END ) ,
TT.FuelChg = ( CASE WHEN LEFT(id.cht_itemcode, 4) = 'FUEL'
THEN FuelChg + id.ivd_charge
ELSE FuelChg + 0
END ) ,
TT.FreightChg = ( CASE WHEN LEFT(id.cht_itemcode, 2) = 'LH'
THEN FreightChg + id.ivd_charge
ELSE FreightChg + 0
END ) ,
TT.Rate = 1
FROM #TTable AS TT
INNER JOIN invoicedetail AS id ON TT.OrderNumber = id.Ord_hdrnumber
Say I have a table with 5 columns,
A, B, C, D, E
that are integers. I want to get the average of all of the fields in that case, that are not 3.
So, on some sample data:
A, B, C, D, E DESIRED RESULT
-------------
1, 1, 4, 4, 3 -> 2.5 (NOT 2.6)
1, 2, 3, 3, 3 -> 1.5 (NOT 2.4)
EDIT: I found a solution.
(
(
IF(A!=3,A,0)
+IF(B!=3,B,0)
+IF(C!=3,C,0)
+IF(D!=3,D,0)
+IF(E!=3,E,0)
)
/
(
IF(A!=3,1,0)
+IF(B!=3,1,0)
+IF(C!=3,1,0)
+IF(D!=3,1,0)
+IF(E!=3,1,0)
)
) as VALUE
Try that:
select avg(CASE WHEN A = 3 then 0 else A end +
CASE WHEN B = 3 then 0 else B end +
CASE WHEN C = 3 then 0 else C end +
CASE WHEN D = 3 then 0 else D end +
CASE WHEN E = 3 then 0 else E end)/
(CASE WHEN A = 3 then 0 else 1 end +
CASE WHEN B = 3 then 0 else 1 end +
CASE WHEN C = 3 then 0 else 1 end +
CASE WHEN D = 3 then 0 else 1 end +
CASE WHEN E = 3 then 0 else 1 end) as av from table1
group by A,B,C,D,E
DEMO HERE