SQL: Return single value with multiple criteria - sql

Maybe a simple question but I don't get the right results so I hope you can help. In this case I have two different tables, one table filled with Order data (OrderID, Supplier and Order Value). The other table is filled with Invoice data (Invoice ID, Supplier, invoice value, Invoice value -10%, Invoice value +10%).
What I need is an overview based on the order table whereby there is a match between Order supplier and invoice supplier + the order value which is in the range of -10% and +10% of the invoice value. It doesn't matter which order belongs to which invoice, I only need to know whether there is a match 'yes' or 'no'.
Example: In the order table you can see row 1 (order 100). It belongs to supplier A and has a value of 10. In the invoice table you can see that row 4 meets the requirements (Supplier = A and order value: 10 -> range between 9 and 11). This should result in a 'Yes'.
Hope you can help!
Thanks in advance,
Greets!
Order table:
Invoice table:

try:
select *
from Order as o
join Invoice as i
on (o.Supplier = i.Supplier and o.Value between i.ValueMinus10Percent and i.ValuePlus10Percent);

If you just need to now if there is a match, use case with exists. However, I'm going to propose returning a matching invoice id. The value will be NULL if there are no matches:
select o.*,
(select i.id
from invoice i
where i.supplier = o.supplier and
o.value between i.value * 0.9 and i.value * 1.1
fetch first 1 row only
) as a_matching_invoice_id
from orders o

You can do this with a subselect:
select *, (select 1 from Supplier s where o.value - 10 > s.value and o.value + 10 < s.value and so on) as YesOrNo from table Order o;

select a.* into temp from order a,invoice b
where a.supplier=b.supplier and a.value=b.value
select *,case when value between min and max then state='yes'
else state='no'
end
from temp

Related

MS-ACCESS / SQL - How to apply where clause in multiple conditions

SELECT Stock.*
FROM Stock
WHERE (
(
(Stock.ComputerPartNumber) In (SELECT [ComputerPartNumber] FROM [Stock] As Tmp GROUP BY [ComputerPartNumber] HAVING Count(*)=2)
)
AND
(
(Stock.EquipmentName)="EquipmentA" Or (Stock.EquipmentName)="EquipmentB")
)
OR (
(
(Stock.ComputerPartNumber) In (SELECT [ComputerPartNumber] FROM [Stock] As Tmp GROUP BY [ComputerPartNumber] HAVING Count(*)=1)
)
AND (
(Stock.EquipmentName)="EquipmentA" Or (Stock.EquipmentName)="EquipmentB"
)
);
I am using the above SQL to achieve below 3 items:-
Find out all of the ComputerPartNumber which used by EquipmentA and/or EquipmentB only
Filter out the query result if the ComputerPartNumber used by equipment other than EquipmentA and EquipmentB.
If the ComputerPartNumber is used by both EquipmentA and EquipmentC, filter out the result also.
However the item 3 cannot be filtered out successfully. What should I do in order to achieve the item3?
Table and Query snapshots are attached. Thanks in advance!
Table
Query
What you need to do is to check if the total number of times a part is used in all pieces of Equipment is equal to the total number of times a part is used by either Equipment A or B:
SELECT S.StorageID, S.ComputerPartNumber, S.EquipmentName, S.Result
FROM Stock AS S
WHERE
(SELECT COUNT(*) FROM Stock AS S1 WHERE S1.ComputerPartNumber=S.ComputerPartNumber)
=(SELECT COUNT(*) FROM Stock AS S2 WHERE S2.ComputerPartNumber=S.ComputerPartNumber AND S2.EquipmentName IN("EquipmentA","EquipmentB"))
Regards,
You can use not exists:
select s.*
from stock as s
where not exists (select 1
from stock as s2
where s2.ComputerPartNumber = s.ComputerPartNumber and
s2.EquipmentName not in ("EquipmentA", "EquipmentB")
);

Conditional left join on max date and where clause in second table

I am attempting to join a customer table with sales table where I show the list of all customers in database and any paid sale the customer might have in the sales tables. Now a customer can have multiple sales rows in the sales table.
This is an example sales record of one customer with multiple sales in the sale tables
while extracting this record I would like to get only the MAX (q_saledatetime) WHERE the q_paidamount is > 0.
as in show me the last time this customer made a payment to us. So in this case row 2 where they paid 8.90 is what I would like to get for that customer. If a customer has no record in the sales table, show their name/details on the list either way.
My failure at the moment is how to include the where clause of the paid amount + max date column.
ATTEMPT A
select DISTINCT ON (q_customer.q_code)
q_customer.q_code, q_customer.q_name, -- customer info
MAX(q_saleheader.q_saledatetime) AS latestDate, q_saleheader.q_paidamount -- saleheader info
FROM q_customer
LEFT JOIN q_saleheader ON (q_customer.q_code = q_saleheader.q_customercode)
group by q_customer.q_code, q_customer.q_name , q_saleheader.q_saledatetime, q_saleheader.q_paidamount
order by q_customer.q_code ASC
which results in
so for Fred Blogg is picking up details from row 4 instead of 2 (first image). As there's no rule for q_paidamount at this point
ATTEMPT B
SELECT
customer.q_code, customer.q_name, -- customer info
sale.q_saledatetime, sale.q_paidamount -- sale info
FROM q_customer customer
LEFT JOIN (SELECT * FROM q_saleheader WHERE q_saledatetime =
(SELECT MAX(q_saledatetime) FROM q_saleheader b1 where q_paidamount > 0 ))
sale ON sale.q_customercode = customer.q_code
which results in
This doesnt seem to be getting any information from the sale table at all.
Update:
After having a closer look at my first attempt I amended the statement and came up with this solution which achieves the same results as Michal's answer. I just curious to know is there any pitfalls or perfomance disadvantages with the following way.
select DISTINCT ON (q_customer.q_code)
q_customer.q_code, q_customer.q_name, -- customer info
q_saleheader.q_saledatetime, q_saleheader.q_paidamount -- saleheader info
FROM q_customer
LEFT JOIN q_saleheader ON (q_customer.q_code = q_saleheader.q_customercode AND
q_saleheader.q_paidamount > 0 )
group by q_customer.q_code, q_customer.q_name , q_saleheader.q_saledatetime,
q_saleheader.q_paidamount
order by q_customer.q_code ASC, q_saleheader.q_saledatetime DESC
main change was adding AND q_saleheader.q_paidamount > 0 on the join and q_saleheader.q_saledatetime DESC to make sure are getting the top row of that related data. As mentioned both Michal's answer and this solution achieve the same results. Just curious about pitfalls in either of the two ways.
Try this query:
SELECT c.q_code,
c.q_name,
CASE WHEN q_saledatetime <> '1900-01-01 00:00:00.000' THEN q_saledatetime END q_saledatetime,
q_paidamount
FROM (
SELECT c.q_code,
c.q_name,
coalesce(s.q_saledatetime, '1900-01-01 00:00:00.000') q_saledatetime, --it will indicate customer with no data
s.q_paidamount,
ROW_NUMBER() OVER (PARTITION BY c.q_code ORDER BY COALESCE(s.q_saledatetime, '1900-01-01') DESC) rn
FROM q_customer c
LEFT JOIN (SELECT q_saledatetime,
q_paidamount
FROM q_saleheader
WHERE q_paidamount > 0) s
ON c.q_code = s.q_customercode
) c WHERE rn = 1

SELECT TOP 10 rows

I have built an SQL Query that returns me the top 10 customers which have the highest outstanding. The oustanding is on product level (each product has its own outstanding).
Untill now everything works fine, my only problem is that if a certain customer has more then 1 product then the second product or more should be categorized under the same customer_id like in the second picture (because the first product that has the highest outstanding contagions the second product that may have a lower outstanding that the other 9 clients of top 10).
How can I modify my query in order to do that? Is it possible in SQL Server 2012?
My query is:
select top 10 CUSTOMER_ID
,S90T01_GROSS_EXPOSURE_THSD_EUR
,S90T01_COGNOS_PROD_NAME
,S90T01_DPD_C
,PREVIOUS_BUCKET_DPD_REP
,S90T01_BUCKET_DPD_REP
from [dbo].[DM_07MONTHLY_DATA]
where S90T01_CLIENT_SEGMENT = 'PI'
and YYYY_MM = '2017_01'
group by CUSTOMER_ID
,S90T01_GROSS_EXPOSURE_THSD_EUR
,S90T01_COGNOS_PROD_NAME
,S90T01_DPD_C
,PREVIOUS_BUCKET_DPD_REP
,S90T01_BUCKET_DPD_REP
order by S90T01_GROSS_EXPOSURE_THSD_EUR desc;
You need to calculate the top Customers first, then pull out all their products. You can do this with a Common Table Expression.
As you haven't provided any test data this is untested, but I think it will work for you:
with top10 as
(
select top 10 CUSTOMER_ID
,sum(S90T01_GROSS_EXPOSURE_THSD_EUR) as TOTAL_S90T01_GROSS_EXPOSURE_THSD_EUR
from [dbo].[DM_07MONTHLY_DATA]
where S90T01_CLIENT_SEGMENT = 'PI'
and YYYY_MM = '2017_01'
group by CUSTOMER_ID
order by TOTAL_S90T01_GROSS_EXPOSURE_THSD_EUR desc
)
select m.CUSTOMER_ID
,m.S90T01_GROSS_EXPOSURE_THSD_EUR
,m.S90T01_COGNOS_PROD_NAME
,m.S90T01_DPD_C
,m.PREVIOUS_BUCKET_DPD_REP
,m.S90T01_BUCKET_DPD_REP
from [dbo].[DM_07MONTHLY_DATA] m
join top10 t
on m.CUSTOMER_ID = t.CUSTOMER_ID
order by t.TOTAL_S90T01_GROSS_EXPOSURE_THSD_EUR desc
,m.S90T01_GROSS_EXPOSURE_THSD_EUR;

Select number of records until the sum is less than 'n' - Access SQL

I am working on Microsoft Access. My requirement is, User will give any percentage value and I have to find the number of IDs which form the percentage of the 'Value' column. For e.g. in the below DataSet (it is sorted by descending of value column which is also required), the sum of all values is '8409131'.
ID NAME VALUE
1000000090 A 2295175
1000000974 B 1942753
1000015555 C 1887965
1000004864 D 1310400
1000015557 E 972838
If I enter 75%, the value is 65170765.25, so I need to return all the IDs which forms the '65170765', less than or equals to. So in this case below are the sum of values which are less than 65170765.
ID NAME VALUE
1000000090 A 2295175
1000000974 B 1942753
1000015555 C 1887965
Is this possible to achieve my requirement in Access SQL?
My plan is to make a running total column to find sum of first two rows and then sum of that value with next row. But in Access, I am not able to figure out how to create incremental rows in select query also to achieve this.
Query I tried:
SELECT T1.ID, T1.NAME, T1.VALUE,(T1.VALUE + T2.VALUE)
FROM (
SELECT ID , RUN_MANAGER.NAME AS NAME, RUN_MANAGER.REPORTING_PERIOD, SUM(VALUE) As VALUE
FROM DATA
INNER JOIN RUN_MANAGER
ON DATA.RUN_NUMBER=RUN_MANAGER.RUN_NUMBER
WHERE RUN_MANAGER.NAME='A'
GROUP BY ID,RUN_MANAGER.NAME
ORDER BY SUM(VALUE) DESC) AS T1
INNER JOIN (
SELECT ID , RUN_MANAGER.NAME AS NAME, RUN_MANAGER.REPORTING_PERIOD, SUM(VALUE) As VALUE
FROM DATA
INNER JOIN RUN_MANAGER
ON DATA.RUN_NUMBER=RUN_MANAGER.RUN_NUMBER
WHERE RUN_MANAGER.NAME='A'
GROUP BY ID,RUN_MANAGER.NAME
ORDER BY SUM(VALUE) DESC) AS T2
ON T1.ID=T2.ID+1
This is not a duplicate question. The problem is, this question is based on Access SQL and also I do not have any incremental ascending rows.
If you have a table like t:
ID NAME VALUE
1000000090 A 2295175
1000000974 B 1942753
1000015555 C 1887965
1000004864 D 1310400
1000015557 E 972838
You can use this query:
SELECT *
FROM t
WHERE
(SELECT SUM(VALUE) FROM t ti WHERE ti.Name <= t.Name) < (SELECT SUM(VALUE) FROM t ti) * 0.75
For this:
ID NAME VALUE
1000000090 A 2295175
1000000974 B 1942753
1000004864 D 1310400

Getting Max Value From Joined Table With Certain Logic

This is my table relation :
tbl_product
-----------
product_id
tbl_product_price
-----------------
price_id
price_product_id (FK)
price_normal
price_discount
price_disc_valid_from_date
price_disc_valid_to_date
I'd like to query tbl_product, ordered by its max price DESC, which must be validated first. If the the discount date is still valid (current date between price_disc_valid_from_date AND price_disc_valid_to_date), then get the price_discount. If not valid, then get price_normal. After that I need to get max price ( either from the price_discount or price_normal), then order by that max price.
Most of the questions like this are just how to select the max column, no validation needed first on the joined table.
My question is , what is the postgres sql statement for that query ? Thanks
[EDIT]
I stuck in selecting max price from table tbl_product_price but no idea how to join with tbl_product :
SELECT
pr.price_id, pr.product_price_id,
CASE WHEN current_date BETWEEN pr.price_disc_valid_from_date AND pr.price_disc_valid_to_date
THEN pr.price_discount
ELSE pr.price_normal END AS price
FROM tbl_product_price pr
WHERE pr.price_product_id = 316
GROUP BY pr.price_id, pr.price_product_id
ORDER BY price DESC
LIMIT 1;
Can you do something like this:
SELECT
tbl_tbl_product.price_product_id,
tblMax.MaxPrice
FROM
tbl_tbl_product
JOIN
(
SELECT
tbl_product_price.price_product_id,
MAX(
CASE
WHEN now() BETWEEN
tbl_product_price.price_disc_valid_from_date
AND tbl_product_price.price_disc_valid_to_date
THEN tbl_product_price.price_discount
ELSE tbl_product_price.price_normal
END
) AS MaxPrice
FROM
tbl_product_price
GROUP BY
tbl_product_price.price_product_id
) as tblMax
ON tblMax.price_product_id=tbl_tbl_product.product_id
ORDER BY
tblMax.MaxPrice DESC
If I understand your logic correctly, this query should return products ordered by the maximum price for the product:
SELECT
tp.product_id
FROM
tbl_product tp INNER JOIN tbl_product_price tpp
ON tb.product_id = tpp.price_product_id
GROUP BY
tp.product_id
ORDER BY
MAX(CASE WHEN current_date BETWEEN tpp.price_disc_valid_from_date
AND tpp.price_disc_valid_to_date THEN
tpp.price_discount
ELSE
tpp.price_normal END) DESC