Filter rows based on condition sql server 2008 - sql

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

Related

Create a group id in SQL Server

I have data in this format
ColA
Date
RSN
ID
DesiredColumn
70
0904
2
0904-2
1
71
0904
3
0904-3
1
100
0904
4
0904-4
1
70
0904
5
0904-5
2
I want to add the DesiredColumn that changes its values every time it sees RTI = 070 in ColA
Can someone please help?
You can use a cumulative sum, something like:
select t.*,
sum(case when colA = 70 then 1 else 0 end) over (partition by date order by rsn)
from t;
I am guessing that you want this per value of date and the ordering is based on rsn. If that is not true, remove the partition by clause.
Sql Fiddle: http://sqlfiddle.com/#!18/59e49/10

how can i alternate between 0 and 1 values in sql server?

I want to create a select which will alternate between 1 and 0
my table looks like that
id1 id2 al
11 1 1
40 1 0
12 1 0
237 1 1
but I want to make it like that
id1 id2 al
40 1 0
11 1 1
12 1 0
237 1 1
I want to keep the same values in my table but I just want to switch the rows to alternate between 0 and 1
Consider:
select *
from mytable
order by row_number() over(partition by al order by id1), al
This alternates 0 and 1 values - if the groups have a different number of rows, then, once the smallest group exhausts, all remaining rows in the other group appear at the end of the resultset.
I am unsure which column you want to use to order the rows within each group - I assumed id1, but you might want to change that to your actual requirement.

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

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.

Some Case statement issue

I have two tables that has data like
table1
Id id_nm
1 per
2 per
3 org
table2
Id Lst_id l_nm up_dt
1 22 abc 9/10/2015
1 21 abs 10/12/2016
2 21 xzc 10/12/2013
2 23 xyz 10/21/2013
2 23 xnh 01/12/2013
Need to pick the l_nm where lst_id is 22. If that is not present then we need to pick the l_nm with the most recent updated date.
Id lst_id lnm up_dt
1 22 abc 9/10/2015
2 23 xyz 10/21/2013
can any one please help me in implementing it.
Simple way is to use row_number with a window clause to generate a custom sort order:
select id, lst_id, l_nm as lnm, up_dt
from (
select id
,lst_id
,l_nm
,up_dt
,row_number()
over (partition by id
order by case when lst_id = 22 then 1 else 2 end
,up_dt desc) as rn
from table2
) where rn = 1;

Referencing the value of the previous calculcated value in Oracle

How can one reference a calculated value from the previous row in a SQL query? In my case each row is an event that somehow manipulates the same value from the previous row.
The raw data looks like this:
Eventno Eventtype Totalcharge
3 ACQ 32
2 OUT NULL
1 OUT NULL
Lets say each Eventtype=OUT should half the previous row totalcharge in a column called Remaincharge:
Eventno Eventtype Totalcharge Remaincharge
3 ACQ 32 32
2 OUT NULL 16
1 OUT NULL 8
I've already tried the LAG analytic function but that does not allow me to get a calculated value from the previous row. Tried something like this:
LAG(remaincharge, 1, totalcharge) OVER (PARTITION BY ...) as remaincharge
But this didn't work because remaingcharge could not be found.
Any ideas how to achieve this? Would need a analytics function that can give me the the cumulative sum but given a function instead with access to the previous value.
Thank you in advance!
Update problem description
I'm afraid my example problem was to general, here is a better problem description:
What remains of totalcharge is decided by the ratio of outqty/(previous remainqty).
Eventno Eventtype Totalcharge Remainqty Outqty
4 ACQ 32 100 0
3 OTHER NULL 100 0
2 OUT NULL 60 40
1 OUT NULL 0 60
Eventno Eventtype Totalcharge Remainqty Outqty Remaincharge
4 ACQ 32 100 0 32
3 OTHER NULL 100 0 32 - (0/100 * 32) = 32
2 OUT NULL 60 40 32 - (40/100 * 32) = 12.8
1 OUT NULL 0 60 12.8 - (60/60 * 12.8) = 0
In your case you could work out the first value using the FIRST_VALUE() analytic function and the power of 2 that you have to divide by with RANK() in a sub-query and then use that. It's very specific to your example but should give you the general idea:
select eventno, eventtype, totalcharge
, case when eventtype <> 'OUT' then firstcharge
else firstcharge / power(2, "rank" - 1)
end as remaincharge
from ( select a.*
, first_value(totalcharge) over
( partition by 1 order by eventno desc ) as firstcharge
, rank() over ( partition by 1 order by eventno desc ) as "rank"
from the_table a
)
Here's a SQL Fiddle to demonstrate. I haven't partitioned by anything because you've got nothing in your raw data to partition by...
A variation on Ben's answer to use a windowing clause, which seems to take care of your updated requirements:
select eventno, eventtype, totalcharge, remainingqty, outqty,
initial_charge - case when running_outqty = 0 then 0
else (running_outqty / 100) * initial_charge end as remainingcharge
from (
select eventno, eventtype, totalcharge, remainingqty, outqty,
first_value(totalcharge) over (partition by null
order by eventno desc) as initial_charge,
sum(outqty) over (partition by null
order by eventno desc
rows between unbounded preceding and current row)
as running_outqty
from t42
);
Except it gives 19.2 instead of 12.8 for the third row, but that's what your formula suggests it should be:
EVENTNO EVENT TOTALCHARGE REMAININGQTY OUTQTY REMAININGCHARGE
---------- ----- ----------- ------------ ---------- ---------------
4 ACQ 32 100 0 32
3 OTHER 100 0 32
2 OUT 60 40 19.2
1 OUT 0 60 0
If I add another split so it goes from 60 to zero in two steps, with another non-OUT record in the mix too:
EVENTNO EVENT TOTALCHARGE REMAININGQTY OUTQTY REMAININGCHARGE
---------- ----- ----------- ------------ ---------- ---------------
6 ACQ 32 100 0 32
5 OTHER 100 0 32
4 OUT 60 40 19.2
3 OUT 30 30 9.6
2 OTHER 30 0 9.6
1 OUT 0 30 0
There's an assumption that the remaining quantity is consistent and you can effectively track a running total of what has gone before, but from the data you've shown that looks plausible. The inner query calculates that running total for each row, and the outer query does the calculation; that could be condensed but is hopefully clearer like this...
Ben's answer is the better one (will probably perform better) but you can also do it like this:
select t.*, (connect_by_root Totalcharge) / power (2,level-1) Remaincharge
from the_table t
start with EVENTTYPE = 'ACQ'
connect by prior eventno = eventno + 1;
I think it's easier to read
Here is a demo