finding unique record using min and max in same query from several criteria - sql

I have a common table expression with the following fields
product.identifier, ingredient.identifier, ingredient.cost,
ingredient.isActive, ingredient.isPrimary
I'm trying to find a record based off the following criteria among multiple records
if isActive = 1 and isPrimary = 1, choose that record
if the record with isPrimary = 1 but isActive = 0, choose the record with the highest/max cost where isPrimary = 0 and isActive = 1
if all records from step 2 have the same cost, choose the oldest/min record based off ingredient.Identifier
the logic to find these on their own is simple but combining the logic into one clause is not working as expected. here is the expected output I'm trying to match along with the incorrect SQL
product ingredient cost isActive isPrimary isChosenRecord
-- isActive and isPrimary example
1 10 1.00 1 1 yes
1 11 1.10 1 0 no
2 20 2.00 1 1 yes
2 22 2.15 1 0 no
-- primary record is inactive, choose max cost record
3 30 3.00 0 1 no
3 31 3.10 1 0 no
3 32 3.20 1 0 yes
4 40 4.00 0 1 no
4 41 4.10 1 0 no
4 42 4.20 1 0 yes
-- primary record is inactive, all records have same cost, choose oldest record
5 50 5.00 0 1 no
5 51 5.00 1 0 yes
5 52 5.00 1 0 no
6 60 6.00 0 1 no
6 61 6.00 1 0 yes
6 62 6.00 1 0 no
; with [ActiveRecordsCTE] as
(
select
ProductIdentifier = p.Identifier,
IngredientIdentifier = i.Identifier,
i.Cost, i.isActive, i.isPrimary
from Product p
inner join Ingredient i on i.Identifier = p.Identifier
where i.isActive = 1
),
[CalculatedPrimaryRecords] AS
(
SELECT
r.ProductIdentifier,
r.IngredientIdentifier
FROM ActiveRecordsCTE r
WHERE r.IsPrimary = 1
UNION
-- get the oldest records
SELECT
r.ProductIdentifier,
IngredientIdentifier = min(r.IngredientIdentifier)
FROM
(
-- get most expensive record by cost
SELECT
r.ProductIdentifier,
r.IngredientIdentifier
FROM ActiveRecordsCTE a
CROSS APPLY
(
-- get most expensive record per product
SELECT
r.ProductIdentifier
,MaxAssetValue = MAX(r.Cost)
FROM ActiveRecordsCTE b
WHERE b.IsPrimary = a.IsPrimary
AND a.ProductIdentifier = b.ProductIdentifier
AND a.IngredientIdentifier = b.IngredientIdentifier
GROUP BY b.ProductIdentifier
) ca
WHERE a.IsPrimary = 0
-- exclude records that are included in the statement above
AND a.ProductIdentifier NOT IN
(
SELECT ProductIdentifier
FROM ActiveRecordsCTE
WHERE IsPrimary = 1
)
) sub
GROUP BY sub.ProductIdentifier
)
select * from [CalculatedPrimaryRecords]

Use row_number() for this type of prioritization:
with cte as ( . . . )
select t.*
from (select cte.*,
row_number() over (partition by product
order by (case when isActive = 1 and isPrimary = 1 then 1
when isActive = 0 and isPrimary = 1 then 2
else 3
end),
cost desc,
identifier asc
) as seqnum
from cte
) t
where seqnum = 1;
This makes some assumptions that seem consistent with the question:
isActive and isPrimary only take on the values 0 and 1.
If no records have isPrimary = 1, then you still want a record. (If not, these can easily be filtered out.)
identifier is not defined in your sample data.
EDIT:
If you wanted to be fancy, you could use top (1) with ties:
select top (1) with ties cte.*
from cte
order by row_number() over (partition by product
order by (case when isActive = 1 and isPrimary = 1 then 1
when isActive = 0 and isPrimary = 1 then 2
else 3
end),
cost desc,
identifier asc
);
I actually prefer the row_number() solution because I'm not sure what to do in the case that isPrimary = 0 and it is easier to add logic for that solution to filter out those records.

Related

Number of Rows Between Polarity Changes SQL

I want to count the number of rows between polarity changes grouped by id in SQL. I'm thinking that there may be a clever way to use window functions to get the job done but I don't know what it is.
Consider data like this:
id
polarity
date
1
0
12/1
1
1
12/2
1
0
12/3
1
0
12/4
1
1
12/5
2
0
12/1
2
0
12/2
2
0
12/3
2
1
12/4
2
0
12/5
2
0
12/6
2
0
12/7
2
1
12/8
Is there a way to count the number of rows between each change in polarity to get something like this :
id
n
1
1
1
2
2
3
2
3
You can do:
select id, count(*) as n
from (
select *,
sum(i) over(partition by id order by date) as g
from (
select *, case when polarity <> lag(polarity)
over(partition by id order by date)
then 1 else 0 end as i
from t
) x
) y
group by id, g
having max(polarity) = 0

Identify a FK which has the highest value from a list of values in its source table

I have following tables.
Part
id
name
1
Part 1
2
Part 2
3
Part 3
Operation
id
name
part_id
order
1
Op 1
1
10
2
Op 2
1
20
3
Op 3
1
30
4
Op 1
2
10
5
Op 2
2
20
6
Op 1
3
10
Lot
id
part_id
Operation_id
10
1
2
11
2
5
12
3
6
I am selecting the results from Lot table and I want to select a column last_Op which is based on the order value of the operation_id. If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
SELECT
id,
part_id,
operation_id,
last_Op
FROM Lot
expected result set based on the tables above.
id
part_id
operation_id
last_op
10
1
2
0
11
2
5
1
12
3
6
1
In above example, first row returns last_op = 0 because operation_id = 2 is associated with part_id = 1 and it has the highest order = 30. Since operation_id for this part is not pointing towards the highest order value, 0 is returned.
The other two rows return 1 because operation_id 5 and 6 are associated with part_id 2 and 3 respectively and they are pointing towards the highest 'order' value.
If value of order for the operation_id is the highest for the respective part_id, return 1 else return 0
This sounds like window functions will help:
select l.*,
(case when o.order = o.max_order then 1 else 0 end) as last_op
from lot l left join
(select o.*,
max(o.order) over (partition by o.part_id) as max_order
from operations o
) o
on l.operation_id = o.id;
Note: order is a very poor name for a column because it is a SQL keyword.

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
);

Filter rows based on condition sql server 2008

The below is the sample data.
Op_ID manual TT
------------------
1 0 32
1 1 38.4
2 0 4.56
2 1 7.5
55 1 50
55 1 30
case 1: i need to check Op_id and manual column, if the manual column is having 0 then i need to take tt value= 32 and ignore the below record. similarly needs to check the other records.i.e. op_id=2 and manual=0 then need to take tt=4.56.
case 2: if both records having manual =1 then i need to take max of tt, i.e tt=50.(for the op_id=55).
So i need the output like below.
Op_ID manual TT
------------------
1 0 32
2 0 4.56
55 1 50
select opid, manual, tt
from (
select *, row_number() over (partition by opid order by manual, tt desc) rn
from yourtable ) v
where rn = 1

Return results where first entry is 1 and all subsequent rows are 0

I m working on weird SQL query
Patient_ID Count order_no
1 1 1
2 1 2
2 0 3
2 0 4
3 1 5
3 0 6
where I need to count the patient as above, for every new patient , the count column is 1.
If repeated , the below entry it should be 0
I m confused how should make that work in SQL
In order to make the first entry 1 and all subsuqent entries 0, I believe you need a ranking with partition by the order number. Please checkout the sqlfiddle below to test results.
http://www.sqlfiddle.com/#!3/4e2e2/17/0
SELECT
patient_id
,CASE WHEN r.rank = 1
THEN 1
ELSE 0
END
, order_number
FROM
(
SELECT
order_number
,patient_id
,ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY order_number)[rank]
FROM
PatientTable
)r