How to return matching column value where only all subqueries are true - sql

I'd like to adjust the below SQL statement so that it only returns the PART_ID where all SELECT PART_ID FROM FABRICATION... conditions are met.
Currently the below statement would return part_id's 1 & 2, when the intent is to only return 1.
Thanks for any advice you can offer.
SELECT *
FROM Part
WHERE Section = 'C6x1_5/8x1/4'
AND Length BETWEEN 41.99 AND 42.01
AND Part.Part_ID IN (SELECT Part_ID FROM Fabrication
WHERE Type LIKE 'HOLE'
AND Face = 1
AND Side = 3
AND Location BETWEEN 2.99 AND 3.01
AND Offset = 2
AND Parameter_1 = 0.5625)
AND Part.Part_ID IN (SELECT Part_ID FROM Fabrication
WHERE Type LIKE 'HOLE'
AND Face = 1
AND Side = 3
AND Location BETWEEN 5.99 AND 6.01
AND Offset = 2
AND Parameter_1 = 0.5625)
Fabrication Table:
PART_ID
TYPE
FACE
SIDE
LOCATION
OFFSET
PARAMETER_1
PARAMETER_2
PARAMETER_3
1
HOLE
1
3
6
2
0.5625
0
0
1
HOLE
1
3
3
2
0.5625
0
0
2
HOLE
1
3
6
2
0.5625
0
0
2
HOLE
1
3
3
2
0.5625
0
0
2
HOLE
1
3
9
2
0.5625
0
0
3
HOLE
1
3
3
2
0.5625
0
0

You can use aggregation and HAVING to validate that there there is exactly one match for each condition and no others:
SELECT *
FROM Part
WHERE Section = 'C6x1_5/8x1/4' AND
Length BETWEEN 41.99 AND 42.01
Part.Part_ID IN (SELECT f.Part_ID
FROM Fabrication f
GROUP BY f.Part_ID
HAVING SUM(CASE WHEN f.Type = 'HOLE' AND f.Face = 1 AND f.Side = 3 AND f.Offset = 2 AND f.Parameter_1 = 0.5625 THEN 1 ELSE 0 END) = COUNT(*) AND
SUM(CASE WHEN Location BETWEEN 2.99 AND 3.01 THEN 1 ELSE 0 END) = 1 AND
SUM(CASE WHEN Location BETWEEN 5.99 AND 6.01 THEN 1 ELSE 0 END) = 1
);

It looks like the only variance in your two queries is Location, for which you want to ensure the number of Fabrication rows meet your criteria and do not have any additional rows outside of your criteria.
One option you can try uses conditional aggregation:
select *
from Part
where Section = 'C6x1_5/8x1/4'
and Length between 41.99 and 42.01
and Part.Part_ID in (
select PART_ID
from Fabrication
where
TYPE = 'HOLE'
and FACE = 1
and SIDE = 3
and offset = 2
and PARAMETER_1 = 0.5625
group by PART_ID
having Count(*)=Sum(case when LOCATION between 2.99 and 3.01 then 1 end) + Sum(case when LOCATION between 5.99 and 6.01 then 1 end)
)

Related

How to reset running counts and start from 1 based on the condition and make previous row values as 0 in SQL?

For example there is some table with below data:
No Id Value
1 100 1
2 100 0
3 100 1
4 100 2
1 101 1
2 101 2
1 102 0
2 102 1
I have to write SQL query, which will return row count based on specific condition. If the value matches 0 then need to reset running counts and start from 1 and make previous row values as 0
So the result will be like:
No Id Value Running Count
1 100 1 0
2 100 0 0
3 100 1 1
4 100 1 2
1 101 1 1
2 101 2 2
1 102 1 0
2 102 0 0
Your sample dataset is quite limited so I'm not sure of all edge cases but see if the following works for you. If not it might help get you there.
This gets a running count using a window & case expression and uses lead to check the next value.
If the current value or next value is 0 the count is 0, otherwise it's the running count subtracting 1 if there is a 0 in the Id block indicating the count was reset.
select No, Id, Value,
case when value = 0 or nv = 0
then 0
else
rc - case when Min(value) over(partition by id) = 0 then 1 else 0 end
end Running_Count
from (
select *,
Sum(case when value = 0 then 0 else 1 end) over(partition by id order by no) rc,
Lead(Value) over(partition by Id order by No)nv
from t
)t;

How to merge grouped records into one row in MS SQL

How can I merge grouped records (byt SurvId) into one single row where Column Mode is part of the column name?
This
ID SurvId Mode A B
---------------------------------------
1 1 Unrestricted 1 3
2 1 Restricted 5 2
3 2 Unrestricted 6 4
4 2 Restricted 4 1
Into this
SurvId UnrestictedA UnrestrictedB RestrictedA RestrictedB
------------------------------------------------------------
1 1 3 5 2
2 6 4 4 1
You can use conditional aggregation:
select survid,
max(case when mode = 'Unrestricted' then A end) as unrestricted_a,
max(case when mode = 'Restricted' then A end) as restricted_a,
max(case when mode = 'Unrestricted' then B end) as unrestricted_b,
max(case when mode = 'Restricted' then B end) as restricted_b
from t
group by survid;

SQL merge 3 tables

I have an sql query involving 2 tables and try to add a third one.
These are the tables
FreeBookPos
FreeBooK_ID
ArticleNr
Amount
FreeBook
ID
BookNr
Date
FreeFields
FreeFieldType
Value
SQLPrimeKey
The first two are linked this way
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr
Now I need to add the table 3. This table is linked via SQLPrimeKey to FeeBook table ID. I then need to have only the fields where FreeFields.Value 2 or 4 and FreeFields.FreeFieldType = 54.
I tried various options with join but never get the result. Would I need to first join table 2 and 3 and then with 1 in a separate step?
Table 1: FreeBookPos
FreeBook_ID ArticleNr Amount
1 145 12
2 145 6
3 143 4
4 145 1
5 145 42
Table 2: FreeBook
ID BookNr Date
1 1 2012-05-19
2 -1 2012-05-21
3 1 2012-05-22
4 -1 2012-05-24
5 -1 2012-06-25
Table 3: FreeFields
SQLPrimareyKey FreeFieldType Value
1 54 1
2 52 2
3 54 4
4 54 2
5 54 2
Result should be:
ArticleNr Dt TotalEntryAmount TotalLeftAmount
143 2012-05 4 0
145 2012-05 0 -1
145 2012-06 0 -42
Try the below -
select FreeBookPos.ArticleNr, Format(FreeBooking.Date, 'yyyy_MM') as dt,
SUM(CASE WHEN FreeBook.BookNr = 0 THEN FreeBookPos.Amount ELSE 0 END) as TotalEntryAmount,
SUM(CASE WHEN FreeBook.BookNr = 1 THEN FreeBookPos.Amount ELSE 0 END) as TotalLeftAmount
From FreeBookPos
INNER JOIN FreeBook on FreeBookPos.FreeBook_ID = FreeBook.ID
inner join FreeFields on FreeBook.ID=SQLPrimareyKey
where value in (2,4) and FreeFieldType = 54
group by FORMAT ( FreeBook.Date, 'yyyy_MM'), FreeBookPos.ArticleNr
order by dt, ArticleNr

Limit sql query to only rows where aggregate of col = 0

I'm looking at auction data in the following form:
product auction_id bid_value is_winning_bid reject_reason
iPhone 123 5 1 0
iPhone 123 3 0 1
iPhone 123 2 0 200
iPad 456 1 0 1
iPad 456 10 0 1
iPhone 789 2 0 200
iPhone 999 10 0 1
I want to count the number of auctions where one of the bids had a reject_reason = 200 and none of the bids has a is_winning_bid = 1, grouped by product.The data set is large so I don't want to have the output grouped by auction_id.
The table above should result in:
product total_auctions count_unfilled_auctions count_unfilled_auctions_200
iPhone 3 2 1
iPad 1 1 0
I think you just need two levels of aggregation, one at the auction level and one at the product level:
select product, count(*) as total_auctions,
sum(1 - has_winning_bid) as unfulfilled_auctions,
sum(case when cnt_reject_200 > 0 and has_winning_bid = 1 then 1 else 0 end) as unfulfilled_auctions_200
from (select auction_id, product,
max(is_winning_bid) as has_winning_bid,
sum(case when reject_reason = 200 then 1 else 0 end) as cnt_reject_200
from auctiondata ad
group by auction_id, product
) ad
group by product;

SQL Query. limit an update per rows if condition is X and Y for the same ID number

Have the following table tblTrans where
Trans_ID Trans Sequence Trans_PointsEarned Trans_PointsApplied
4452 1 1 1
4452 2 1 1
4452 3 0 1
4462 1 1 1
4462 2 1 1
4462 3 1 1
4462 4 1 1
4462 5 1 1
9101 1 0 1
9101 2 0 1
9101 3 0 1
9101 4 0 1
(useless table doesnt work)
I need to set the following on another field per every customer ID.
So Customer_OverallPoints
4452 = 2 (doesn't count 0's)
4462 = 4 (I want to cap the points to 4 based on the sequence and transID and customerID)
9101 = 0 (dont count 0's).
This needs to be applied to thousands of records based on customerID and TransID where Trans_Sequence is within the same Trans_ID and it only counts the first 4 rows that have the Trans_pointsEarned = 1.
I tried putting a psuedocode together but it just looked ridicilous and I can't even come up with the logic for this.
Thanks
Assuming that TransId is really the customer id, I think the basic logic is just an aggregation:
select t.TransId,
(case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end) as Customer_OverallPoints
from tblTrans t
group by t.TransId;
You can put this into an update statement as:
update customers c
set Customer_OverallPoints = (select (case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end)
from tblTrans t
where t.TransId = c.CustomerId
);