How to display only few columns of a table based on the data - sql

Consider the table below
Name partno. sch_date WO# owed panels
aa 1234 08/22/2017 121 22 26
aa 1234 08/22/2017 222 22 27
aa 1234 08/22/2017 242 22 27
aa 1234 08/29/2017 152 20 24
aa 1234 08/29/2017 167 20 24
aa 1234 08/29/2017 202 20 26`
Is it possible to display the data in such way that when the number of panels is greater than owed, then i don't won't to dispaly the other partno. schedule on the same date(sch_date).
Expected Result
Name partno. sch_date WO# owed panels
aa 1234 08/22/2017 121 22 26
aa 1234 08/29/2017 152 20 24

Cross apply may help here. (note you can see why I asked about order in my earlier comment as the ORDER of records in a table is not guaranteed! we need to know in what you want the records evaluated! Date isn't enough (unless it has a time compoent not displayed that is different!)
WORKING example on Rextester: http://rextester.com/CAUK18185
Many assumptions made:
When owned is > panels you don't need to see the record.
You want to see the the lowest WO# when owed is < panels and suppress all other records including ones where owed > panels.
If there are no records for a date, name and partno that have owed < panels, you want to see no records.
If these assumptions are incorrect, please provide a better sample set and expected results to test these types of situations and explain what you want to have happen.
SELECT Distinct B.*
FROM tblName Z
CROSS APPLY (SELECT TOP 1 A.*
FROM tblName A
WHERE A.owed < A.panels
and Z.Name = A.Name
and Z.[partno.] = a.[partno.]
and Z.sch_date = a.sch_date
ORDER by A.name, A.[partno.], A.sch_date, A.[wo#]) B
For each record in A run a query which returns the lowest wo# for a name, partno and sch_date when the owed < panels.
UPDATED:
I see in a comment you want to keep records if owed > panels... if it's encountered first.... but what if it's not encountered first?
http://rextester.com/NXS51018
--First we get all the records w/ a owed < panels per group and assign the earliest row (that having the lowest WO) a RN of 1. then we return that set.
cte as (
Select A.*, row_number() over (Partition by Name, [partno.], sch_date ORDER BY [WO#]) RN
from tblName A
where owed < panels)
Select * from cte where RN =1
UNION ALL
--We then union in the records where owed >=panels and their WO# < the wo# from the CTE.
SELECT Z.*, 0 as rn FROM tblName Z where owed >=panels
and exists (Select * from cte
where Z.name = CTE.name
and Z.[partno.] = cte.[partno.]
and Z.sch_date = cte.sch_date
and CTE.[WO#] > Z.[WO#]) --Now this line may not be needed, depending on if you want all or just some of the WO#'s when owed >=panels.
ORDER BY name, [partno.], Sch_date, [Wo#]
After last comment update:
cte as (
Select A.*, row_number() over (Partition by Name, [partno.], sch_date ORDER BY [WO#]) RN
from tblName A
where owed < panels),
cte2 as (Select * from cte where RN =1
UNION ALL
SELECT Z.*, 0 as rn FROM tblName Z where owed >=panels
and exists (Select * from cte
where Z.name = CTE.name
and Z.[partno.] = cte.[partno.]
and Z.sch_date = cte.sch_date
and CTE.[WO#] > Z.[WO#]))
Select * into SOQ#45619304 from CTE2; --This line creates the table based on the 2nd cte results.
Select * from SOQ#45619304;

You can try this -
SELECT Name, partno., sch_date, WO#, owed, panels
FROM YOUR_TABLE
WHERE panels < owed
UNION ALL
SELECT Name, partno., sch_date, MIN(WO#), owed, MIN(panels)
FROM YOUR_TABLE
WHERE panels > owed
GROUP BY Name, partno., sch_date, owed
ORDER BY Name

Related

How to filter out rows based on information in other columns and rows

I have a pricing policy table that determines the price a customer is given based on qty purchased as per below.
debtor_code
stock_code
min_quantity
default_price
contract_price
2393
GRBAG100GTALL-50
0
295
236
2393
GRBAG100GTALL-50
5
295
265.5
2393
GRBAG100GTALL-50
10
295
221.25
The pricing offered is based on the cheapest contract_price available for the lowest qty, meaning that the second row is obsolete as the min_quantity, and the cheaper price from the first row overrides the second row.
How can I use a SQL Server query to filter out obsolete rows like this as the first row supersedes it by having a cheaper contract_price at a lower min_quantity.
The result should look like:
debtor_code
stock_code
min_quantity
default_price
contract_price
2393
GRBAG100GTALL-50
0
295
236
2393
GRBAG100GTALL-50
10
295
221.25
use LEAD() to find the next tier's contract_price and compare with current level. Set the flag and filter out accordingly in the final query.
Based on assumption that price at higher tier (higher min_quantity value) should be cheaper than current tier.
with cte as
(
select *,
case when lead(contract_price) over (partition by debtor_code
order by min_quantity) < contract_price
then 1
else 0
end as flag
from pricing
)
select *
from cte
where flag = 0
dbfiddle demo
EDIT :
The following query uses recursive cte to compare current row with previous row to determine the validity of the price
with cte as
(
select *, rn = row_number() over (partition by debtor_code, stock_code
order by min_quantity)
from pricing
),
rcte as
(
select debtor_code, stock_code, rn, min_quantity, default_price,
contract_price,
valid_price = contract_price, valid = 1
from cte
where rn = 1
union all
select c.debtor_code, c.stock_code, c.rn, c.min_quantity, c.default_price,
c.contract_price,
valid_price = case when c.contract_price < r.contract_price
then c.contract_price
else r.contract_price
end,
valid = case when c.contract_price < r.contract_price
then 1
else 0
end
from rcte r
inner join cte c on r.rn = c.rn - 1
)
select *
from rcte
where valid = 1
dbfiddle demo
Edit 2
A much simplified solution. First is to find the min(contract_price) in the sequence of min_quantity. Then simply compare the current contract_price with that. It is same or equal, it is valid
select *
from
(
select *, valid_price = min(contract_price)
over (partition by debtor_code, stock_code
order by min_quantity)
from pricing
) p
where contract_price <= valid_price
dbfiddle demo

Oracle SQL Group by and sum with multiple conditions

I attached a capture of two tables:
- the left table is a result of others "Select" query
- the right table is the result I want from the left table
The right table can be created following the next conditions:
When the same Unit have all positive or all negative
energy values, the result remain the same
When the same Unit have positive and negative energy values then:
Make a sum of all Energy for that Unit(-50+15+20 = -15) and then take the maximum of absolut value for the Energy.e.g. max(abs(energy))=50 and take the price for that value.
I use SQL ORACLE.
I realy appreciate the help in this matter !
http://sqlfiddle.com/#!4/eb85a/12
This returns desired result:
signs CTE finds out whether there are positive/negative values, as well as maximum ABS energy value
then, there's union of two selects: one that returns "original" rows (if count of distinct signs is 1), and one that returns "calculated" values, as you described
SQL> with
2 signs as
3 (select unit,
4 count(distinct sign(energy)) cnt,
5 max(abs(energy)) max_abs_ene
6 from tab
7 group by unit
8 )
9 select t.unit, t.price, t.energy
10 from tab t join signs s on t.unit = s.unit
11 where s.cnt = 1
12 union all
13 select t.unit, t2.price, sum(t.energy)
14 from tab t join signs s on t.unit = s.unit
15 join tab t2 on t2.unit = s.unit and abs(t2.energy) = s.max_abs_ene
16 where s.cnt = 2
17 group by t.unit, t2.price
18 order by unit;
UNIT PRICE ENERGY
-------------------- ---------- ----------
A 20 -50
A 50 -80
B 13 -15
SQL>
Though, what do you expect if there was yet another "B" unit row with energy = +50? Then two rows would have the same MAX(ABS(ENERGY)) value.
A union all might be the simplest solution:
with t as (
select t.*,
max(energy) over (partition by unit) as max_energy,
min(energy) over (partition by unit) as min_energy
from t
)
select unit, price, energy
from t
where max_energy > 0 and min_energy > 0 or
max_energy < 0 and min_enery < 0
union all
select unit,
max(price) keep (dense_rank first order by abs(energy)),
sum(energy)
from t
where max_energy > 0 and min_energy < 0
group by unit;

Find out the last updated record in my DB using MAX in CASE statement

I have APPLICATIONSTATUSLOG_ID primary key field on my table.
In order to find out the last updated record in my DB and the MAX(APPLICATIONSTATUSLOG_ID) is presumed to be the most recent record.
I tried this code :
SELECT
MAX(CASE WHEN MAX(d.ApplicationStatusLog_ID) = d.ApplicationStatusLog_ID THEN d.ApplicationStatusID END) AS StatusID,
FROM
ApplicationStatusLog d
But I get error:
Msg 130, Level 15, State 1, Line 53 Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My table looks like
ApplicationID - ApplicationStatusID - ApplicationStatusLogID
10000 17 100
10000 08 101
10000 10 102
10001 06 103
10001 10 104
10002 06 105
10002 07 106
My output should be:
10000 10
10001 10
10002 07
Please help me understand and resolve my problem.
If you want to just find the last updated row, given that it has max value in APPLICATIONSTATUSLOG_ID column. The query would be:
SELECT *
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT
So as you stated in comment, the query for it will be:
DECLARE #statusId INT
SELECT #statusId = STATUSID
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT 2:
The query as per your edit in question will be:
WITH C AS
(
SELECT ApplicationID,ApplicationStatusID,ApplicationStatusLogID, ROW_NUMBER() OVER (PARTITION BY ApplicationID ORDER BY ApplicationStatusLogID DESC) AS ranking
FROM ApplicationStatusLog
)
SELECT ApplicationID,ApplicationStatusID
FROM C
WHERE ranking = 1
You can join same table twice like this:
select IT.JoiningID, JT.MAXAPPLICATIONSTATUSID FROM dbo.[Table] IT
INNER JOIN (
Select JoiningID, MAX (APPLICATIONSTATUSID) MAXAPPLICATIONSTATUSID
FROM dbo.[Table]
GROUP BY JoiningID
) JT ON IT.JoiningID = JT.JoiningID
Now you have MAXAPPLICATIONSTATUSID per ID so you can write what you wand based on MAXAPPLICATIONSTATUSID.
Without full query
SELECT
x.StatusId
...
FROM <Table> a
CROSS APPLY
(
SELECT x.APPLICATIONSTATUSID as StatusId
FROM <Table> x
HAVING MAX(APPLICATIONSTATUSLOG_ID) = a.APPLICATIONSTATUSLOG_ID
GROUP BY x.APPLICATIONSTATUSID
)

Join tables based on dates with check

I have two tables in PostgreSQL:
Demans_for_parts:
demandid partid demanddate quantity
40 125 01.01.17 10
41 125 05.01.17 30
42 123 20.06.17 10
Orders_for_parts:
orderid partid orderdate quantity
1 125 07.01.17 15
54 125 10.06.17 25
14 122 05.01.17 30
Basicly Demans_for_parts says what to buy and Orders_for_parts says what we bought. We can buy parts which do not list on Demans_for_parts.
I need a report which shows me all parts in Demans_for_parts and how many weeks past since the most recent matching row in Orders_for_parts. note quantity field is irrelevent here,
The expected result is (if more than one row per part show the oldes):
partid demanddate weeks_since_recent_order
125 01.01.17 2 (last order is on 10.06.17)
123 20.06.17 Unhandled
I think the tricky part is getting one row per table. But that is easy using distinct on. Then you need to calculate the months. You can use age() for this purpose:
select dp.partid, dp.date,
(extract(year from age(dp.date, op.date))*12 +
extract(month from age(dp.date, op.date))
) as months
from (select distinct on (dp.partid) dp.*
from demans_for_parts dp
order by dp.partid, dp.date desc
) dp left join
(select distinct on (op.partid) op.*
from Orders_for_parts op
order by op.partid, op.date desc
) op
on dp.partid = op.partid;
smth like?
with o as (
select distinct partid, max(orderdate) over (partition by partid)
from Orders_for_parts
)
, p as (
select distinct partid, min(demanddate) over (partition by partid)
from Demans_for_parts
)
select p.partid, min as demanddate, date_part('day',o.max - p.min)/7
from p
left outer join o on (p.partid = o.partid)
;

Select min values for an id and for entire table in ONE query

I want to find the lowest visited value for a specific id AND the lowest for entire table.
In one query.
MyTab
ID VISITED
101 2009
102 2010
103 2011
104 2012
105 2013
Can I do it in one query?
Right now I do like:
select
min(visited)
from
mytab
where
id = 100;
and then I do the second query.
select
min(visited)
from
mytab;
What I want is something like below (but can one make it more simple?)
select
min( a.visited ),
min( b.visited )
from
(select visited from mytab where id=100) as a,
(select visited from mytab) as b;
Query run for e.g. id 103 and 100 would be:
id 103 will give 2011,2009
id 100 will give null,2009
Thanks
You can use MIN with CASE:
select
min(case when id = 100 then visited end) minbyid,
min(visited) minoverall
from mytab
SQL Fiddle Demo
select min(visited) as GlobalMin
, min(case when id = 100 then visited end) as MinForId100
from mytab