finding specific customers in contract table - sql

I am working with MS SQL and need help creating a query.
I have a table called CustomerContracts, in it is multiple lines per item# for specific customers.
For example real data
item cust_num
x 1156
x 3924
x 7565
x 84339
x 104365
x 106066
x 107377
x 118691
y 1156
y 3924
y 7565
y 84339
y 104365
y 106066
y 107377
So what I need to do is search the table by item number and a specific customer number and return the item if that customer number does not exist as a record for that item.
So, in this case I am checking all item records for the cust_num of 106066 and 118691 if the item does not contain both customers then I want it to be included in my results so in this cause item X would not show up, but item Y would.
I think I need to do some type of count. I have tried using NOT IN(002,003) no luck.
Suggestions?
to satisfy my attempt at this. I have tried at least 8 different ways, this is the latest attempt.
select 'Cust Does not exist' as Status,
i.item as item,
i.description as description,
t.numcusts
From
item i inner join (select count(cust_num) as numcusts,item
from itemcust
where cust_num NOT IN ('106066','118691')
group by item) t on t.item = i.item
where i.stat = 'A' and t.numcusts > 0
order by i.item,i.description
did not work. So, I am still trying to resolve it. I was able to develop a sort of solution using imbedded queries in Access, but can't get the sql it created to port over.

I am guessing that you have multiple records for a customer. You want customers where the table has no record for a given item. One approach is to use group by and having:
select cc.cust_num
from CustomerContracts cc
where c.cust_num in ('001', '002')
group by cc.cust_num
having sum(case when cc.cust_item_num in ('aaa') then 1 else 0 end) = 0;
Another approach is to use not exists:
select cc.*
from CustomerContract cc
where c.cust_num in ('001', '002') and
not exists (select 1 from CustomerContracts where cust_item_num in ('aaa'));
The first gives a list of customer number. The second gives all the records for those customers.
EDIT (based on edit to question):
The question is about items not customers. A modification to the first approach will work. If you only want items that have at least one of the customers, then use a where clause:
select cc.cust_item_num
from CustomerContracts cc
where c.cust_num in (106066, 118691)
group by cc.cust_item_num
having count(distinct c.cust_num) < 2;
If you want all items (even where neither customer appears), then count each customer match separately in the having clause:
select cc.cust_item_num
from CustomerContracts cc
group by cc.cust_item_num
having sum(case when c.cust_num = 106066 then 1 else 0 end) = 0 or
sum(case when c.cust_num = 118691 then 1 else 0 en) = 0;

Thanks for the help, but after 5 cups of coffee and 2 playlists I figured it out
select 'Cust Does not exist' as Status,
i.item as item,
i.description as description,expr1
From
item i RIGHT join (select itemcust.item,
sum(case when LTRIM(RTRIM(cust_num)) = '106066' or LTRIM(RTRIM(cust_num)) ='118691'then 1 else 0 end) as expr1
from itemcust
group by itemcust.item) t on t.item = i.item
where i.stat = 'A' AND expr1 <> 2
order by i.item,i.description
This gives me all the items that do not have both records or actually have them more than once.

Related

Does it matter to filter results when doing aggregation?

I want to get my sales for each day which is located in my orders_summary table.
orders_summary table columns: id, date, amount, sku_id
products table columns: id, sku
Currently Im getting my daily sales like this:
SELECT
MAX(CASE WHEN os.date = '01/01/2022' THEN COALESCE(amount,0)::INT ELSE 0 END) AS orders_1,
MAX(CASE WHEN os.date = '01/02/2022' THEN COALESCE(amount,0)::INT ELSE 0 END) AS orders_2
FROM products AS p
LEFT JOIN orders_summary AS os ON p.id = os.sku_id
WHERE p.id = '1'
GROUP BY p.id;
Is it important to add AND date BETWEEN '01/01/2022' AND '01/02/2022' in my where clause?
Yes absolutely. Imagine having 10 years worth of data in the table where you're only interested in the data for two days. You must use the where clause which restricts the number of rows (down to 0.05% in this case) before doing the group by.

select sum where condition is true and count > 3

I have two tables.
FootballPlayers with columns Id_footballplayer, Last_Name, Fisrt_Name, Age
Transfers with columns Id_transfer, Name_club, price, date, acceptance (yes or no), code_footballplayer
How can I write a SQL query to select the last names of the players and the sum of the successful transfers carried out by them, the number of which exceeds 3?
I already wrote a query that displays the total amount of all successful transfers for each player
SELECT FootballPLayers.Last_Name,
SUM(CASE acceptance WHEN 'yes' THEN price ELSE 0 END) AS amount_price
FROM FootballPlayers
INNER JOIN Transfers ON FootballPlayers.ID_footballplayer = Transfers.code_footballplayer
GROUP BY FootballPlayers.Last_Name;
But I don’t know how to add a condition if the number of successful transfers is more than 3
Since this is a group scenario, after theGROUP BY you probably want:
HAVING COUNT(1) > 3
The HAVING clause works very similarly to WHERE, but is applied differently.
An alternative would be the sub-query:
SELECT * FROM
(
SELECT FootballPLayers.Last_Name,
SUM(CASE acceptance WHEN 'yes' THEN price ELSE 0 END) AS amount_price,
COUNT(1) AS [Transfers]
FROM FootballPlayers
INNER JOIN Transfers ON FootballPlayers.ID_footballplayer = Transfers.code_footballplayer
GROUP BY FootballPlayers.Last_Name
) x
WHERE x.Transfers > 3

Determining if a sample contains 0 rows for multiple ID's

So I've created a simple query that will pass all OrdID's that have orders of 2 or more apples:
SELECT ordid
FROM results
WHERE ordid IN (12,24,53,21,41,51)
AND product = 'apples'
GROUP BY ordid
HAVING COUNT(ordid) > 1
How can I do this for OrdID's that contain 0 apples?(This doesn't work as there is no product on the OrdID by apples, so it passes 0 rows.) I'd like it to list all OrdID's that have < 1 products for Apples.
SELECT ordid
FROM results
WHERE ordid IN (12,24,53,21,41,51)
AND product = 'apples'
GROUP BY ordid
HAVING COUNT(ordid) < 1
I cannot reproduce in my machine but I hope that this query should work:
SELECT ordid
FROM results
WHERE ordid in (12,24,53,21,41,51)
GROUP BY ordid
HAVING SUM(CASE WHEN product = 'apples' THEN 1 ELSE 0 END) < 1
I switched the HAVING with a COUNT() of the products instead of the orderid since youre trying to count the number of products.
SELECT ordid
FROM results
WHERE ordid in (12,24,53,21,41,51) and product = 'apples'
GROUP BY ordid
HAVING COUNT(product) = 0
The problem you're running into is that you're selecting FROM a table (i.e., limiting to those rows) where what you want to match is what's not in the table (i.e., excluding those rows). These are opposites.
Instead, flip that around so you're selecting FROM the set of values and then excluding those that match:
SELECT ordid FROM (VALUES (12),(24),(53),(21),(41),(51)) AS ordids(ordid)
WHERE NOT EXISTS (
SELECT * FROM results
WHERE results.ordid = ordids.ordid
AND results.product = 'apples'
)
This will return a result for an ordid even if that value never appears in the results table at all.
Use the EXISTS() function to get all OrdIDs WHERE there does NOT EXIST a correlated row with product = 'apples'

Return a Complete sales order where a given item is purchased SQL

I'm trying to query our Sales_Order_Line_Item table. We are introducing a new "Tariff" Item code, our sales staff are required to add this code to all orders that have items that start with "WI". So I need to create a query that will show me any orders that have item codes that start with "WI" but are missing the "Tariff" code.
I can't seem to figure out how to return a list that shows this data.
For simplicity, my Sales_Order_Line_Item Table has these 3 columns:
UNIQUE_LINE_ID, SALE_ORDER_#, ITEM_#
One dirty trick is to use a case expression and count the number of times these items appear:
SELECT sale_order_no
FROM sales_order_line_item
GROUP BY sale_order_no
HAVING COUNT(CASE WHEN item_code LIKE 'WI%' THEN 1 END) > 0 AND
COUNT(CASE WHEN item_code = 'Tarrif' THEN 1 END) = 0
Should be something like this:
select * from Sales_Order_Line_Item
where ItemCode like 'wi%'
and tariff is null
If, you want full order details you can use EXISTS/NOT EXISTS instead :
select so.*
from sales_order_line_item so
where exists (select 1 from sales_order_line_item sol where sol.sale_order_no = s.sale_order_no and sol.item_code LIKE 'WI%') and
not exists (select 1 from sales_order_line_item sol where sol.sale_order_no = s.sale_order_no and sol.item_code = 'Tarrif');

Group by unknown values using SQL

I have a table called "shipment" and a table called "order". The order and the shipment are related using the table "order_movement". So, in this last table, there will be the shipment_id and the order_gid.
In the shipment table I have the name of the carrier (servprov_gid). What I want to do is to group all the order basing on the name of the carrier. Simple until this point. Here is my query:
select count(distinct order_release_gid) X, servprov_gid Y
from
(select distinct ord.order_release_gid, ship.servprov_gid
from order_release ord,
shipment ship,
order_movement om,
where ship.shipment_gid = om.shipment_gid
and om.order_release_gid = ord.order_release_gid
and ship.servprov_gid in ('CNHILA.CAVL_CCWB','CNHILA.PRLG_CCPL','CNHILA.TCXS_CCWB','CNHILA.RDWY_CCWB', 'CNHILA.WAWL_CCWB'))
group by servprov_gid
please, forget about the query form, it's not the focus of the question. So now I have all the order for a certain carrier, choosen in that list. But now I'd like to know, in the same query, all the orders by other carriers! What I'd expect is a table containing
0. X | Y
1. 1 | CNHILA.CAVL_CCWB
2. ...
3. 6 | OTHER
it's possible? Thank you
EDIT
my expected output is a "6-row" table containing the number of the orders for the 5 carrier specified in the "IN" clause and the number of all the other orders (the ones which have a different carrier)!
0. X | Y
1. 1 | CNHILA.CAVL_CCWB
2. 2 | CNHILA.PRLG_CCPL
3. 0 | CNHILA.TCXS_CCWB
4. 2 | CNHILA.RDWY_CCWB
5. 12 | CNHILA.WAWL_CCWB
6. 6 | OTHER
Skip doing the in list in the where clause, you are going to read everything anyway. Instead use a case statement to transform everyone that is not in the in list to OTHER:
select count(order_release_gid) X, servprov_gid Y
from
(select distinct ord.order_release_gid,
case
when ship.servprov_gid in ('CNHILA.CAVL_CCWB','CNHILA.PRLG_CCPL','CNHILA.TCXS_CCWB','CNHILA.RDWY_CCWB', 'CNHILA.WAWL_CCWB')
then ship.servprov_gid
else 'OTHER'
end servprov_gid
from order_release ord,
shipment ship,
order_movement om,
where ship.shipment_gid = om.shipment_gid
and om.order_release_gid = ord.order_release_gid
)
group by servprov_gid
order by case servprov_gid when 'OTHER' then 2 else 1 end
, servprov_gid
The case in the order by is only to insure that the OTHER row always is the last row.
You need to manually provide the same value to all of the OTHER providers so that you can group them. One way would be to use the DECODEfunction:
select
count(distinct order_release_gid) X,
ShipmentGroupID Y
from
(select distinct
ord.order_release_gid,
decode(ship.servprov_gid,
'CNHILA.CAVL_CCWB', 'CNHILA.CAVL_CCWB',
'CNHILA.PRLG_CCPL', 'CNHILA.PRLG_CCPL',
'CNHILA.TCXS_CCWB', 'CNHILA.TCXS_CCWB',
'CNHILA.RDWY_CCWB', 'CNHILA.RDWY_CCWB',
'CNHILA.WAWL_CCWB', 'CNHILA.WAWL_CCWB',
'OTHER') ShipmentGroupID
from
order_release ord,
shipment ship,
order_movement om
where
ship.shipment_gid = om.shipment_gid
and om.order_release_gid = ord.order_release_gid
)
group by
ShipmentGroupID
The decode function works like a CASE statement. The first parameter to the function is the value to be compared, then you follow with with pairs of values, the first of each pair is compared to the first parameter and if it matches then the second of the pair is returned. The extra parameter at the end is the default if no matches are found.
So if the provider is 'CNHILA.PRLG_CCPL' it will return 'CNHILA.PRLG_CCPL', but if the provider is 'CNHILA.IJustMadeThisUp' it will return 'OTHER' because none of the pairs given in the decode function matched it.
Your query though won't return a shipment method that is never used and your sample results contain a shipment provider with a count of 0.
This query can be rewritten to get those results, and you don't even need the order table:
select
count(distinct order_release_gid) X,
ShipmentGroupID Y
from
(select distinct
om.order_release_gid,
decode(ship.servprov_gid,
'CNHILA.CAVL_CCWB', 'CNHILA.CAVL_CCWB',
'CNHILA.PRLG_CCPL', 'CNHILA.PRLG_CCPL',
'CNHILA.TCXS_CCWB', 'CNHILA.TCXS_CCWB',
'CNHILA.RDWY_CCWB', 'CNHILA.RDWY_CCWB',
'CNHILA.WAWL_CCWB', 'CNHILA.WAWL_CCWB',
'OTHER') ShipmentGroupID
from
shipment ship
LEFT JOIN order_movement om ON ship.shipment_gid = om.shipment_gid
)
group by
ShipmentGroupID