SQL exclude all rows that with have certain value? - sql

i have a table with these value, and here is a small sample
order state item id
10064315 ON MCM1L162L116
10064315 ON MCM1R162R116
10064315 ON SHIPPING
10064316 MS 00801-1778
10064316 MS SHIPPING
10064317 AZ CHM110439-1
10064317 AZ SHIPPING
10064318 TX 2607
10064318 TX SHIPPING
10064319 MO CHG8080
10064319 MO SHIPPING
10064322 CA W10001130
I want to write a sql query that only list on the order number that without SHIPPING, in this sample, the only one without SHIPPING would be 10064322.
I try to find in here but didn't find what I am looking for.
Thank for the help

SELECT DISTINCT [order]
FROM MYTABLE
WHERE [order] not in (SELECT [order]
FROM MYTABLE
WHERE [item id] = 'SHIPPING')
EDIT:
According to Aaron Bertrand's article (hat tip #TTeeple in the comments) the best performance for this problem (needing the distinct) is done as follows:
SELECT [order]
FROM MYTABLE
EXCEPT
SELECT [order]
FROM MYTABLE
WHERE [item id] = 'SHIPPING'
For the full article -> http://sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join

One option is to use not exists:
select ordernumber
from yourtable y
where not exists (
select 1
from yourtable y2
where y.ordernumber = y2.ordernumber and y2.itemid = 'SHIPPING'
)

Use conditional aggregation:
select [order] from
table
group by [order]
having sum(case when [item id] = 'SHIPPING' then 1 else 0 end) = 0

Related

Conditionally use CASE...WHEN - Oracle SQL

I have two tables like so:
tblOrders: OrderNo (pk), CurrentStepNo (fk)
tblSteps: StepNo (pk), OrderNo (fk), StepName, StepType, StepStart, StepStop
tblOrders contains tons of information about our sales orders, while tblSteps contains tons of information regarding the proper sequential steps it takes to build the material we are selling.
I am trying to construct a query that follows this logic:
"For all orders, select the current step name from the step table. If
the Step Type is equal to 'XO', then select the most recently
completed (where StepStop is not null) regular step (where StepStop is
equal to 'YY')"
I have the following query:
SELECT
tblOrders.*,
tblSteps.StepName
FROM
tblOrders
INNER JOIN tblSteps
ON tblOrders.OrderNo = tblSteps.OrderNo
AND tblOrders.CurrentStepNo = tblSteps.StepNo
Which successfully returns to me the current step name for an in-process order. What I need to achieve is, when the tblOrders.CurrentStepNo is of type 'XO', to find the MAX(tblSteps.StepStop) WHERE tblSteps.StepType = 'YY'. However, I am having trouble putting that logic into my already working query.
Note: I am sorry for the lack of sample data in this example. I would normally post but cannot in this instance. This is also not a homework question.
I have reviewed these references:
Case in Select Statement
https://blogs.msdn.microsoft.com/craigfr/2006/08/23/subqueries-in-case-expressions/
But no luck so far.
I have tried this:
SELECT
tblOrders.*,
CASE
WHEN tblSteps.StepType = 'XO' THEN (-- Some logic here)
ELSE tblSteps.StepName
END AS StepName
FROM
tblOrders
INNER JOIN tblSteps
ON tblOrders.OrderNo = tblSteps.OrderNo
AND tblOrders.CurrentStepNo = tblSteps.StepNo
But am struggling to properly formulate the logic
Join all steps, rank them with ROW_NUMBER, and stay with the best ranked:
select *
from
(
select
o.*,
s.*,
row_number() over
(partition by o.orderno
order by case when s.steptype <> 'XO' and s.stepno = o.currentstepno then 1
when s.steptype <> 'YY' then 2
else 3 end, s.stepstop desc nulls last) as rn
from tblorders o
join tblsteps s on s.orderno = o.orderno
) ranked
where rn = 1
order by orderno;

Selecting customer IDs who have purchased from a certain channel

I'm trying to pull a list of customer IDs who have purchased online only and another list of those who have purchased both online and in-store (no customers for in-store only). I currently have a table that looks like this:
-------------------------------------------------------
**customerid** **shipped_dt** **channel**
1 2018-10-31 online
1 2018-11-01 store
2 2018-11-01 store
3 2018-11-01 online
3 2018-11-02 online
In this case, for the list with those who have purchased both online and in-store, I was customerid 1. For the list of customers that are online only, I want customerid 3. How exactly would I go about writing a code for this? I'm still learning SQL so I'm not too knowledgeable about the proper syntax and abilities within SQL.
I only want a return of customerid and the channel that they purchased through.
Thank you!
If you have a separate list of customers, you might want to use exists:
For example, to get customers who have purchased in both places:
select c.*
from customers c
where exists (select 1 from t where t.customer_id = c.customer_id and t.channel = 'online'
) and
exists (select 1 from t where t.customer_id = c.customer_id and t.channel = 'store'
) ;
This can have some advantages over aggregation:
exists and not exists can make direct use of an index on (customer_id, store).
You can get customers who purchased in neither channel.
You can get additional information about the customer, if that is desirable.
Just a minor alternative
Example
Select customerid
,Channel = min(Channel)
From YourTable
Group By customerid
Having min(Channel)=max(channel)
and min(Channel)='online'
Note: If you remove and min(Channel)='online' you would see customers who purchased through only one channel
Returns
customerid Channel
3 online
For the case of 'online' only customers use not exists to exclude those who have purchased in 'store':
select distinct customerid
from tablename t
where not exists (
select 1 from tablename where customerid = t.customerid and channel = 'store'
)
For the case of 'online' and 'store':
select distinct customerid
from tablename t
where
(select count(distinct channel) from tablename where customerid = t.customerid) = 2
You can combine the above queries into this:
select distinct customerid, 'online' channel
from tablename t
where not exists (
select 1 from tablename where customerid = t.customerid and channel = 'store'
)
union all
select distinct customerid, 'both' channel
from tablename t
where
(select count(distinct channel) from tablename where customerid = t.customerid) = 2
See the demo

Asking to enter a parameter value that already exists

I have a three column table of price breaks called "FPB" that looks like this:
[Part Number] [Quantity] [Price]
AAA-AAAA     100   1.23
AAA-AAAA     200   1.15
BBB-BBBB     100   5.60
CCC-CCCC      500   3.21
....
Where each part number has multiple entries in multiple rows.
I'm trying to reorganize the table to look more like this
[Part Number] [Quantity1] [Price 1] [Quantity 2] [Price 2] [Quantity 3....
AAA-AAAA      100   1.23    200    1.15   ....
BBB-BBBB      100   5.60     ...
CCC-CCCC       500   3.21    ...
...
Where each part number has all its entries combined into one row. The first quantity column should have the lowest available quantity, the second should have the second smallest etc. I am trying to do this by first creating a 1-column table with just the unique part numbers using GROUP BY, and then creating more tables for each column that has the information I want in that column, and then joining it by Part Number. The problem comes when calculating the second smallest quantity for each type, done in the second to last section.
SELECT PNs.[Part Number], Q1T.Q1, P1T.Price, Q2T.Q2
FROM
(SELECT
[Part Number]
FROM FPB
GROUP BY [Part Number]
) AS PNs,
(SELECT
[Part Number],
MIN(Quantity) AS Q1
FROM FPB
GROUP BY [Part Number]
) AS Q1T,
(SELECT
*
FROM FPB
) AS P1T,
(SELECT
[Part Number],
MIN(IIF(Quantity>Q1T.Q1,Quantity)) AS Q2
FROM FPB
GROUP BY [Part Number]
) AS Q2T
WHERE
PNs.[Part Number] = Q1T.[Part Number]
AND P1T.[Part Number] = PNs.[Part Number]
AND P1T.Quantity = Q1T.Q1
AND Q2T.[Part Number] = PNs.[Part Number]
When I run this query, it asks me to enter a parameter value for Q1T.Q1, even though it already exists. If I remove the code section for Q2T, as well as any references to Q2, it will work without a problem, and it won't ask about a value for the other instances of Q1T.Q1. Why doesn't Q1T.Q1 have a value just for that section, and how can I fix it? As a side note, I'm using the SQL features of a program called PHPRunner, and its client doesn't support UPDATE/DELETE/INSERT/CREATE queries, UNION, and DISTINCT.
You're looking for something like this.
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
From there it's easy to pivot in order to insert into a new table:
into into NewFPB (PartNumber, Quantity1, Price1, Quantity2, Price2, ...)
select
PartNumber,
min(switch(PriceTier = 1, UpperQuantity)) as Quantity1,
min(switch(PriceTier = 2, UpperQuantity)) as Quantity2, ...
min(switch(PriceTier = 1, Price)) as Price1,
min(switch(PriceTier = 2, Price)) as Price2, ...
from (
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
) data
You might have to tweak it a little bit for Access to accept it. But the core ideas are there.
The query you call is incorrect.
Q1T is inner select statement , and in Q2T (other inner select statement) , you can't use any field from Q1T
The SQL Server raise error: Incorrect syntax near ')'.
To overcome this limitation , you should use Common Table Expressions CTE
for PNs, Q1T, P1T, Q2T
CTE is like dynamic view.
It's a new feature since sql 2008 and It's a very powerful.
review: https://technet.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
Try to Draw a relational data model for these four CTE to be sure that a relation exist between them based on your where conditions.
I think the logic in this query may raise runtime error during execution:
e.g. The multi-part identifier "Q1T.Q1" could not be bound.
Edit:
For Ms-Access you can create four queries for: PNs, Q1T, P1T, Q2T every one is in a separate query, and the fifth query join these queries and add where conditions.
In this case you will not get any syntax error. and will get Data model with relation free :) .
As per your question, by the time you define the derived table Q2T, Q1T is still an invalid object. You need to try to work around this issue.
EDIT:
Suppose you only got 2-level columns to handle, the code is listed below, i tested it. It works well.
select q5.*,q3.quantity, q3.price
from
(select *
from FPB as Q1
where 0 = (select count(distinct(quantity)) from FPB as Q2 where Q2.quantity < Q1.quantity AND Q2.[part number] = Q1.[part number])) as Q5
,
(
select distinct(temp.[part number]),Q2.quantity, Q2.price from FPB as temp
left join
(select *
from FPB as Q4
where 1 = (select count(distinct(quantity)) from #test as Q2 where Q2.quantity < Q4.quantity AND Q2.[PART NUMBER] = Q4.[PART NUMBER])) as Q2
on temp.[PART NUMBER] = Q2.[PART NUMBER]
) as Q3
where Q5.[PART NUMBER] = Q3.[PART NUMBER]

Need to do tthis in 1 SQL

I have to process in an sql as follows. each order is made up of many detail rows. I only need to look at one table, TRA99.
Order number TRAN CODE
123 QEE
123 #23
123 ABC
SELECT
ALL OTRIDC, OTCOM#, OTORD#, OTFL50, OTTRND, OTTRT, OTENT#,
OTSFX#,
OTREL#, OTUSRN, OTTRNC, OTTRN$, OTFL01
FROM ASTDTA.OETRANOT T01
WHERE OTTRNC IN ('QEE', 'QNE')
I want all the Order # which have 'QEE' or 'QNE'. These are QUote codes. We want a report that will tell us, which quotes orders' converted to a real order and which did not.
then if they have as well #23, this tells me that the order was converted or became an actual order. I am not sure how to do this in 1 sql query i was thinking to create a view for all QEE and QNE codes. then run a second query against that looking for #23.
Based on what I think you're trying to do. This will give you all the order numbers which are associated with both QEE or QNE and #23
SELECT T1.OrderNumber
FROM TRA99 T1
WHERE T1.OrderNumber in (
SELECT OrderNumber
FROM TRA99
WHERE TCode IN ('QEE','QNE')
)
AND T1.TCode='#23'
GROUP BY T1.OrderNumber
What you need to do is use a GROUP BY also a EXISTS sub-query can check for the existence of your flag
select t1.[Order Number]
,(CASE WHEN EXISTS(select *
from TRA99 as t2
where t1.[Order Number] = t2.[Order Number]
and t2.[Tran Code] = '#23')
THEN
cast(1 as bit)
ELSE
cast(0 as bit)
END) as HasFlag
from TRA99 as t1
where t1.[Tran Code] in ('QFE', 'QNE')
group by t1.[Order Number]
Working example
NOTE: you did not list what DBMS you are using so I wrote this against Microsoft Sql Server syntax, but you can translate this concept to any DBMS you need.

Creating columns from a select query

SELECT TOP 20
TMPPO.PurchaseOrder ,
TMPPO.LineItem ,
ASLD.SignatureDate ,
ASLD.SignatureTime ,
ASLD.Operator ,
ASLD.Variable ,
ASLD.VariableDesc ,
ASLD.VarNumericValue
FROM #POAMENDMENTS TMPPO
LEFT OUTER JOIN [SysproCompanyR].[dbo].[AdmSignatureLogDet] ASLD ON TMPPO.TransactionId = ASLD.TransactionId
AND TMPPO.SignatureDate = ASLD.SignatureDate
AND TMPPO.SignatureTime = ASLD.SignatureTime
WHERE YEAR(TMPPO.SignatureDate) = 2013
AND MONTH(TMPPO.SignatureDate) = 08
AND VariableDesc IN ( 'Previous foreign price', 'Previous price',
'Foreign price', 'Price' )
ORDER BY PurchaseOrder ,
LineItem
I have the following table but don't want to return the records as per below.
Under the column heading Variable Desc I have Foreign Price, Previous foreign pirce, previous price and price I would like to make these as headings the replace Variable, Variable Desc and VarNumberic.
So e.g. for the first line would be
Purchase Order LineItem SignatureDate SignatureTime Operator PrevFPrice FPrice PrevPrice Price
002074 0001 2013-02-23 9523598 UPOFA0 19.68 21.51 19.68 21.51
004931 0001 2013-08-09 7485253 PVWYK0 980.00 840.00 980.00 840.00
Sorry but is difficult to put sample data here no idea how to...
Is this possible?
#Bummi it provides me data like this, why is Purchase Order 005331 duplicating so many times when in essence according to the original sample data it changed only 2 times according to date and time
From what I am understanding you are looking for a join over your first query
;With CTE as
(
SELECT TOP 20 TMPPO.PurchaseOrder, TMPPO.LineItem, ASLD.SignatureDate,ASLD.SignatureTime,ASLD.Operator, ASLD.Variable, ASLD.VariableDesc, ASLD.VarNumericValue FROM #POAMENDMENTS TMPPO
LEFT OUTER JOIN [SysproCompanyR].[dbo].[AdmSignatureLogDet] ASLD ON TMPPO.TransactionId = ASLD.TransactionId and TMPPO.SignatureDate = ASLD.SignatureDate and TMPPO.SignatureTime = ASLD.SignatureTime
WHERE YEAR(TMPPO.SignatureDate) = 2013
and MONTH(TMPPO.SignatureDate) = 08
and VariableDesc IN ('Previous foreign price','Previous price','Foreign price','Price')
ORDER BY PurchaseOrder, LineItem
)
Select c1.PurchaseOrder,c1.LineItem,c1.SignatureDate,c1.SignatureTime,c1.Operator
,c1.VarNumericValue as [Previous foreign price]
,c2.VarNumericValue as [Previous price]
,c3.VarNumericValue as [Foreign price]
,c4.VarNumericValue as [Price]
FROM CTE c1
JOIN CTE c2 on c2.PurchaseOrder=c1.PurchaseOrder and c2.VariableDesc='Previous price'
and c2.LineItem=c1.LineItem and c2.SignatureDate=c1.SignatureDate and c2.SignatureTime=c1.SignatureTime
JOIN CTE c3 on c3.PurchaseOrder=c1.PurchaseOrder and c3.VariableDesc='Foreign price'
and c3.LineItem=c1.LineItem and c3.SignatureDate=c1.SignatureDate and c3.SignatureTime=c1.SignatureTime
JOIN CTE c4 on c4.PurchaseOrder=c1.PurchaseOrder and c4.VariableDesc='Price'
and c4.LineItem=c1.LineItem and c4.SignatureDate=c1.SignatureDate and c4.SignatureTime=c1.SignatureTime
Where c1.VariableDesc='Previous foreign price'
You can just use 'AS' to rename your columns
SELECT something AS somethingelse