Remove unnecessary rows with different status degree - sql

OrderNumber
OrderStatus
560
0002
560
0016
560
0028
180
0002
180
0215
180
0485
So the order status numbers represents different status' like 0002 means the order object is created, 0485 means order has been completed etc. What I wanted to achieve is if an order is completed or cancelled, I don't want to see any other status of the order like object creation. I have three tables. Let's call them A,B and C. OrderNumber is from table A and OrderStatus from table C . And table B is the joint table where I keep my OrderNo and OrderStat.
select A.OrderNumber, C.OrderStatus
from(A inner join B on B.OrderNo = A.OrderNo
inner join C on C.OrderStatus = B.OrderStat)
where A.OrderNumber in (this is where I need some help I think);```

You can go for CTE to get all the completed orders. Now, you can filter these orders in your resultset and show the completed orders only with completed status.
Note: Based on the question content, I have only considered completed orders. You can add cancelled orders also to the CTE, by adding cancelled Order Status.
;WITH CTE_CompletedCancelledOrders AS
(
SELECT OrderNumber, OrderStatus FROM B
WHERE B.OrderStatus = '0485' -- completedOrders
)
select A.OrderNumber, C.OrderStatus
from A inner join B on B.OrderNo = A.OrderNo
inner join C on C.OrderStatus = B.OrderStatus
WHERE NOT EXISTS (SELECT 1 FROM CTE_CompletedCancelledOrders
WHERE OrderNumber = A.OrderNumber) -- only incomplete Orders
UNION ALL
SELECT * FROM CTE_CompletedCancelledOrders -- completed Orders

The best approach is probably window functions:
select o.*
from (select A.OrderNumber, C.OrderStatus,
sum(case when C.OrderStatus in ('0485', . . . ) then 1 else 0 end) over (partition by A.OrderNumber) as completed_or_canceled
from A inner join
B
on B.OrderNo = A.OrderNo inner join
C
on C.OrderStatus = B.OrderStat
) o
where completed_or_canceled = 0 or
OrderStatus in ('0485', . . . );
The . . . is for the statuses that define the completed/canceled conditions.

Related

Problem optimizing sql query with cross apply sub query

So I have three tables:
MakerParts, that holds the primary information of a Vehicle Part:
Id
MakerId
PartNumber
Description
1
1
ABC1234
Tire
2
1
XYZ1234
Door
MakerPrices, that holds the price history variation for the parts (references MakerParts.Id on MakerPartNumberId, and the table MakerPriceUpdates on UpdateId):
Id
MakerPartNumberId
UpdateId
Price
1
1
1
9.83
2
1
2
11.23
MakerPriceUpdates, that holds the date of prices updates. This update is basically a CSV file that is uploaded to our system. One file, one line on this table, multiple prices changes on the table MakerPrices.
Id
Date
FileName
1
2019-01-09 00:00:00.000
temp.csv
2
2019-01-11 00:00:00.000
temp2.csv
This means that one part (MakerParts) may have multiple prices (MakerPrices). The date of the price change is on the table MakerPricesUpdates.
I want to select all MakerParts where the most recent price is zero, filtering by the MakerId on table MakerParts.
What I've tried:
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId where
MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as p
where mp.MakerId = 1 and p.Price = 0
But that is absurdly slow (we have about 100 million lines on the MakerPrices table). I'm having a hard time optimizing this query. (the result is only two rows for the MakerId 1, and it took 2 mins to run). I also tried:
select * from (
select
mp.*,
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId
where MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as Price
from MakerParts mp) as temp
where temp.Price = 0 and MakerId = 1
Same result, and same time. My query plan (for the first query) (no new indexes suggested by Management Studio):
I think you can avoid joining MakerPriceUpdates with makerprices since with the highest
UpdateId you can find the latest price updates. It will save you some time.
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices where
MakerPrices.MakerPartNumberId = mp.Id order by MakerPrices.UpdateId desc) as p
where mp.MakerId = 1 and p.Price = 0
You can further reduced some times by avoiding sort and order by with cte and row_number() as below:
;with LatestMakerPrices as
(
select *,row_number()over(partition by MakerPartNumberId order by updateid desc)rn from MakerPrices
)
select mp.* from MakerParts mp cross apply
(select price from LatestMakerPrices lmp where lmp.MakerPartNumberId=mp.Id) as p
where mp.MakerId = 1 and p.Price = 0
Execution plan difference between query in question and my answer:
try:
WITH tab AS (
SELECT *, NULL as Price FROM MakerParts
WHERE not exists (
SELECT Id
FROM MakerPrices
WHERE MakerPrices.MakerPartNumberId = MakerParts.Id
)
)
SELECT * from tab WHERE MakerId = 2
UNION ALL
SELECT a.* , Price
FROM [dbo].[MakerParts] a
LEFT JOIN [dbo].[MakerPrices] b
ON b.MakerPartNumberId = a.Id
WHERE MakerId = 2 AND Price = 0
Try your query:
select mp.* from MakerParts mp cross apply
(select top 1 Price from MakerPrices inner join
MakerPricesUpdates on MakerPricesUpdates.Id = MakerPrices.UpdateId where
MakerPrices.MakerPartNumberId = mp.Id order by Date desc) as p
where mp.MakerId = 1 and p.Price = 0
After creating below index:
CREATE NONCLUSTERED INDEX [NCIdx_MakerPrices_MakerPartNumberId_UpdateId] ON [dbo].[MakerPrices]
(
[MakerPartNumberId] ASC,
[UpdateId] ASC
)
INCLUDE([Price])
And making ID column of MakerPricesUpdates table primary key.

Optimize query with a subquery With Group BY MAX and JOINED with another TABLE

I need help to optimize this SQL query, so that it would run much faster.
What I am trying to do is, get the latest values of DATA out of these tables:
TABLE: Quotes
ID QuoteNumber LastUpdated(inticks) PolicyId
1 C1000 1000000000000 100
1 D2000 1001111111110 200
2 A1000 1000000000000 300
2 B2000 1002222222222 400
TABLE: Policies
ID CustomerName Blah1(dummy column)
100 Mark someData
200 Lisa someData2
300 Brett someData3
400 Goku someData4
DESIRED RESULT:
LastUpdated Id(quoteId) QuoteNumber CustomerName
1001111111110- -1- -D2000- -Lisa
1002222222222- -2- -B2000- -Goku
Select DISTINCT subquery1.LastUpdated,
q2.Id,
q2.QuoteNumber,
p.CustomerName
FROM
(Select q.id,
Max(q.LastUpdated) from Quotes q
where q.LastUpdated > #someDateTimeParameter
and q.QuoteNumber is not null
and q.IsDiscarded = 0
GROUP BY q.id) as subquery1
LEFT JOIN Quotes q2
on q2.id = subquery1.id
and q2.LastUpdated = subquery1.LastUpdated
INNER JOIN Policies p
on p.id = q2.PolicyId
where p.blah1 = #someBlahParameter
ORDER BY subquery1.LastUpdated
Here is the actual execution plan:
https://www.brentozar.com/pastetheplan/?id=SkD3fPdwD
I think you're looking for something like this
with q_cte as (
select q.Id, q.QuoteNumber, q.LastUpdated,
row_number() over (partition by q.id order by q.LastUpdated desc) rn
from Quotes q
where q.LastUpdated>#someDateTimeParameter
and q.QuoteNumber is not null
and q.IsDiscarded=0)
select q.*, p.CustomerName
from q_cte q
join Policies p on q.PolicyId=p.id
where q.rn=1 /* Only the lastest date */
and p.blah1=someBlahParameter
order by q.LastUpdated;

Sql code for distinct fields

I was wondering if anyone can help me with this query.
I have two tables that I join together (DDS2ENVR.QBO AND KCA0001.ORTS)
THE QBO Table has a field labeled NIIN AND RIC. THE KCA0001.ORTS table has a field named SERVICE and OWN_RIC.
I Join the tables by QBO.RIC and ORTS.OWN_RIC. My dilemma is that under the NIIN field multiple rows can be identical but have different values for RIC.
Example:
NIIN RIC
123455 A
122222 B
123456 C
122222 A
I want to query a distinct count for NIINS that separates by the different service where it does not overlap. So example NIIN should only find distinct values only associated with A where the same NIIN is not found in B,C,D etc.
SELECT D.SERVICE, COUNT(C.NIIN)
FROM DDS2ENVR.QBO C
JOIN KCA0001.ORTS D ON D.OWN_RIC = C.RIC
WHERE C.SITE_ID = ('HEAA')
GROUP BY D.SERVICE
HAVING COUNT(DISTINCT C.NIIN) > 1
Please ask questions if this does not make any sense.
Using Not Exists
SELECT D.SERVICE, COUNT(C.NIIN)
FROM DDS2ENVR.QBO C
JOIN KCA0001.ORTS D ON D.OWN_RIC = C.RIC
WHERE C.SITE_ID = ('HEAA')
and NOT EXISTS (Select 1 from DDS2ENVR.QBO C1 where C1.NIIN = C.NIIN and C1.RIC <> C.RIC)
GROUP BY D.SERVICE
HAVING COUNT(DISTINCT C.NIIN) > 1
Also if the table DDS2ENVR.QBO doesn't contain duplicates and your dbms supports CTE
With cte as
(Select NIIN from DDS2ENVR.QBO group by NIIN having count(*) = 1)
SELECT D.SERVICE, COUNT(C.NIIN)
FROM DDS2ENVR.QBO C
JOIN KCA0001.ORTS D ON D.OWN_RIC = C.RIC
WHERE C.SITE_ID = ('HEAA')
and C.NIIN in (Select * from cte)
GROUP BY D.SERVICE
HAVING COUNT(DISTINCT C.NIIN) > 1

Incorrect count value in subquery on table join column

The query I'm executing seems to be ignoring the where clause in the subquery
(select count(amazon) from orders where b.amazon = 2 and manifest = a.dbid)
column amazon is type INT
SQL SERVER 2014
If I run the query on its own and enter the value for manifest I get the correct result which I am expecting and is 1
select count(amazon) from orders where amazon = 2 and manifest = '211104'
Result Returns 1
When I run the query below I get a result of 5 which is the count of all orders where manifest = 211104 but the value of amazon is 1 in 4 results and 2 in 1 result.
Select distinct
top 30 DBID, today ,sum([amazon-orders])
From
(
SELECT [dbid], [today],
(select count(amazon) from orders
where b.amazon = 2 and manifest = a.dbid) as [amazon-orders]
FROM [manifest] a
join orders b on a.[dbid] = b.[manifest]
) t1
Group By
DBID, today
order by dbid desc
Can someone please help me.
Thanks
You have an extra join so you are counting multiple times... do this:
Select distinct
top 30 DBID, today ,sum([amazon-orders])
From
(
SELECT [dbid], [today],
(select count(amazon) from orders b
where b.amazon = 2 and manifest = a.dbid) as [amazon-orders]
FROM [manifest] a
) t1
Group By
DBID, today
order by dbid desc
or like this
SELECT [dbid], [today], count(o.amazon)
FROM [manifest] a
join orders o on a.dbid = o.manifest and o.amazon = 2
group by dbid, today
or this if you have columns you don't want to join (there is more going on than just this one join in your query and you need to use a left join):
SELECT [dbid], [today], sum(case when o.amazon is not null then 1 else 0 end)
FROM [manifest] a
left join orders o on a.dbid = o.manifest and o.amazon = 2
group by dbid, today
How's this?
SELECT top 30 [dbid], [today], sum(case when b.amazon = 2 then 1 else 0 end) as [amazon-orders]
FROM [manifest] a
join orders b on a.[dbid] = b.[manifest]
group by DBID, today
order by dbid desc
Pretty sure that because your query is in effect joining orders twice it's increasing the count.
Use this :
select a.DBID, a.today, count(b.amazon) from [manifest] a
join orders b on a.[dbid] = b.[manifest] and b.amazon = 2
Group By a.DBID, a.today

Using (IN operator) OR condition in Where clause as AND condition

Please look at following image, I have explained my requirements in the image.
alt text http://img30.imageshack.us/img30/5668/shippment.png
I can't use here WHERE UsageTypeid IN(1,2,3,4) because this will behave as an OR condition and fetch all records.
I just want those records, of first table, which are attached with all 4 ShipmentToID .
All others which are attached with 3 or less ShipmentToIDs are not needed in result set.
Thanks.
if (EntityId, UsageTypeId) is unique:
select s.PrimaryKeyField, s.ShipmentId from shipment s, item a
where s.PrimaryKeyField = a.EntityId and a.UsageTypeId in (1,2,3,4)
group by s.PrimaryKeyField, s.ShipmentId having count(*) = 4
otherwise, 4-way join for the 4 fields,
select distinct s.* from shipment s, item a, item b, item c, item d where
s.PrimaryKeyField = a.EntityId = b.EntityId = c.EntityId = d.EntityId and
a.UsageTypeId = 1 and b.UsageTypeId = 2 and c.UsageTypeId = 3 and
d.UsageTypeId = 4
you'll want appropriate index on (EntityId, UsageTypeId) so it doesn't hang...
If there will never be duplicates of the UsageTypeId-EntityId combo in the 2nd table, so you'll never see:
EntityUsageTypeId | EntityId | UsageTypeId
22685 | 4477 | 1
22687 | 4477 | 1
You can count matching EntityIds in that table.
WHERE (count(*) in <tablename> WHERE EntityId = 4477) = 4
DECLARE #numShippingMethods int;
SELECT #numShippingMethods = COUNT(*)
FROM shippedToTable;
SELECT tbl1.shipmentID, COUNT(UsageTypeId) as Usages
FROM tbl2 JOIN tbl1 ON tbl2.EntityId = tbl1.EntityId
GROUP BY tbl1.EntityID
HAVING COUNT(UsageTypeId) = #numShippingMethods
This way is preferred to the multiple join against same table method, as you can simply modify the IN clause and the COUNT without needing to add or subtract more tables to the query when your list of IDs changes:
select EntityId, ShipmentId
from (
select EntityId
from (
select EntityId
from EntityUsage eu
where UsageTypeId in (1,2,3,4)
group by EntityId, UsageTypeId
) b
group by EntityId
having count(*) = 4
) a
inner join Shipment s on a.EntityId = s.EntityId