How to display rows that when added together equal zero - sql

Been searching for a few weeks for a solution to this but have come up blank.
I have table of data similar to this:
client_ref supplier_key client_amount
1111 GBP 10
1111 GBP -10
1111 EUR 50
2222 CHF -22.5
2222 CHF -20
3333 EUR -27
3333 EUR -52
3333 EUR 79
I need to extract all items where the client_ref and supplier_key match and the total of the client_amount equals zero. The output would look like this:
client_ref supplier_key client_amount
1111 GBP 10
1111 GBP -10
3333 EUR -27
3333 EUR -52
3333 EUR 79
I have written the following that returns the totals but I need any help you could provide to change this to show the rows that make up the totals rather than just the overall results.
SELECT tbis.client_ref ,tbis.supplier_key ,sum(tbis.client_amount)
FROM [XXXX].[dbo].[transaction] tbis
WHERE tbis.tbis.client_amount !=0
GROUP BY tbis.client_ref, tbis.supplier_key
HAVING sum(tbis.client_amount) =0
ORDER BY sum(tbis.client_amount)
Hope this makes sense and my first post is OK. Please feel free to critique my post.

Try this instead:
SELECT t1.*
FROM transactions AS t1
INNER JOIN
(
SELECT
tbis.client_ref ,
tbis.supplier_key,
sum(tbis.client_amount) AS total
FROM transactions tbis
WHERE tbis.client_amount !=0
GROUP BY tbis.client_ref, tbis.supplier_key
HAVING sum(tbis.client_amount) =0
) AS t2 ON t1.client_ref = t2.client_ref
AND t1.supplier_key = t2.supplier_key
ORDER BY t2.total;
SQL Fiddle Demo

One possible approach is to use the SUM() windowing function:
SELECT *
FROM
( SELECT tbis.client_ref ,tbis.supplier_key,tbis.client_amount,
SUM(tbis.client_amount) OVER (
PARTITION BY tbis.client_ref, tbis.supplier_key) AS total_client_amount
FROM [XXXX].[dbo].[transaction] tbis
WHERE tbis.client_amount !=0
)
WHERE total_client_amount = 0
SQL Fiddle

SELECT client_ref ,supplier_key ,sum(client_amount)
FROM transaction
WHERE client_amount <> 0
GROUP BY client_ref, supplier_key
HAVING sum(client_amount) = 0

SELECT
*
FROM
tbis
INNER JOIN
(
SELECT
client_ref, supplier_key
FROM
tbis
GROUP by client_ref, supplier_key
HAVING sum(client_amount) = 0
) match
ON match.client_ref = tbis.client_ref
AND match.supplier_key = tbis.supplier_key
Demo at http://sqlfiddle.com/#!3/a3447/8/0

SELECT t.* FROM Table1 AS t INNER JOIN
(SELECT [client_ref], [supplier_key], SUM([client_amount]) as Total
FROM Table1 GROUP BY [client_ref], [supplier_key]) AS sumTable
ON t.[client_ref] = sumTable.[client_ref] AND
t.[supplier_key] = sumTable.[supplier_key]
WHERE Total = 0;
SAMPLE FIDDLE

Make a new query for the data you want and join it by inner join to the query that produces the sums to restrict it to the lines you want.

Related

sql Query to find different record in a column

I have table with 5 OR 6 COLUMNS and I need to use the below 2 columns to get the result
col1 col2
Acc1 USD
ACC1 GBP
ACC1 EUR
ACC2 USD
Result:
I need to find out if a acc has more than 2 currency, but the base currency is USD. I need to find out those records which has USD plus other currency if I have only USD accounts then it should not come in my result.
With the information provided this could be an answer:
SELECT col1
FROM tab
GROUP BY col1
HAVING count(*) > 1
Not the best solution but should do the job.
with cte as
(
SELECT t1.[col1],t1.[col2],(select count(t2.col1) from accounts t2 where t2.col1=t1.col1) as AllCurrency
from accounts t1
)
SELECT distinct cte.col1 from cte where cte.AllCurrency>1

Tracing original Value through Iteration SQL

Suppose there is a data collection system that, whenever a record is altered, it is then saved as a new record with a prefix (say M-[most recent number in que and is unique]).
Suppose I am given the following data set:
Customer | Original_Val
1 1020
2 1011
3 1001
I need to find the most recent value for each customer given the following table:
Customer | Most_Recent_Val | Pretained_To_Val | date
1 M-2000 M-1050 20170225
1 M-1050 M-1035 20170205
1 M-1035 1020 20170131
1 1020 NULL 20170101
2 M-1031 1011 20170105
2 1011 NULL 20161231
3 1001 NULL 20150101
My desired output would be:
Customer | Original_Val | Most_Recent_Val | date
1 1020 M-2000 20170225
2 1011 M-1031 20170105
3 1001 1001 20150101
For customer 1, there are 4 levels i.e (M-2000 <- M-1050 <- M-1035 <- 1020) Note that there would be no more than 10 levels of depth for each customer.
Much Appreciated! Thanks in advance.
Find the min and max of each customer and then join it together. Something like this:
Select
[min].Customer
,[min].Most_Recent_Val as Original_Val
,[max].Most_Recent_Val as Most_Recent_Val
,[max].date
From
(
Select
Customer
,Most_Recent_Val
,date
From
table t1
inner join (
Select
Customer
,MIN(date) as MIN_Date
From
table
Group By
Customer
) t2 ON t2.Customer = t1.Customer
and t2.MIN_Date = t1.Date
) [min]
inner join (
Select
Customer
,Most_Recent_Val
,date
From
table t1
inner join (
Select
Customer
,MAX(date) as MAX_Date
From
table
Group By
Customer
) t2 ON t2.Customer = t1.Customer
and t2.MAX_Date = t1.Date
) [max] ON [max].Customer = [min].Customer

Joining 2 tables by latest date

2 tables
select * from general_data
ID | currecny | DATE_ACT
1 USD 01/12/2015
2 USD 02/12/2015
3 GBP 01/12/2015
4 GBP 03/12/2015
5 USD 06/12/2015
select * from currency_data
currecny | RATE_DATE | Rate
USD 04/12/2015 3.51
USD 02/12/2015 3.46
GBP 01/12/2015 4.62
USD 01/12/2015 3.50
I want to match ID to it's valid currency.
Currency is matched by currency name, and 'date'.
--if there is no such date in 'currency_data' table, it should be matched to previous date.
So desired output:
ID | rate |
1 3.50
2 3.46
3 4.62
4 4.62
5 3.51
My attempt:
SELECT gd.ID,
(SELECT rate
FROM currency_data cd
WHERE cd.currecny = gd.currecny
AND gd.date_act >= cd.rate_date
AND ROWNUM = 1
order by cd.rate_date) rate
FROM general_data gd
order by 1
Getting syntax error on order by, but I need order to get the latest.
This is a pain to do in Oracle. In Oracle 12g, you can use fetch first 1 row only:
SELECT gd.ID,
(SELECT rate
FROM currency_data cd
WHERE cd.currecny = gd.currecny AND
gd.date_act >= cd.rate_date
ORDER BY cd.rate_date
FETCH FIRST 1 ROW ONLY
) rate
FROM general_data gd
ORDER BY 1;
But that only works with the most recent release. Unfortunately, using two subqueries to use rownum is problematic, because Oracle's scoping rules do not allow nested correlations.
But, there is a solution:
SELECT gd.ID,
(SELECT MAX(rate) KEEP (DENSE_RANK FIRST ORDER BY cd.rate_date)
FROM currency_data cd
WHERE cd.currecny = gd.currecny AND
gd.date_act >= cd.rate_date
) rate
FROM general_data gd
ORDER BY 1;
KEEP to the rescue.
SELECT gd.ID, cd.Rate
FROM general_data gd
LEFT OUTER JOIN currency_data cd
ON cd.currency = gd.currency
AND cd.rate_date =
(
SELECT max(rate_date)
FROM currency_data cd
WHERE cd.currency = gd.currency
AND cd.rate_date <= gd.date_act
)
ORDER BY 1
Try it on SQLFIDDLE

Zero Fill Data for Missing Dates

I have two tables:
Cust Sales Week
123 4 1/8/2015
123 3 1/22/2015
234 4 1/1/2015
.
Week
1/1/2015
1/8/2015
1/15/2015
1/22/2015
I want to combine them so that every Cust has every date and where there are no Sales it is filled with 0.
Cust Sales Week
123 4 1/1/2015
123 0 1/8/2015
123 0 1/15/2015
123 3 1/22/2015
234 4 1/1/2015
234 0 1/8/2015
234 0 1/15/2015
234 0 1/22/2015
Is there a way I can 'select distinct(Cust)' and join them somehow?
First, generate the rows you want using a cross join. Then bring in the data you want using a left join:
select c.cust, w.week, coalesce(t.sales, 0) as sales
from weeks w cross join
(select distinct cust from t) c left join
t
on t.cust = c.cust and t.week = w.week;
You can left join on the dates table and use isnull on the sales column. Use an equivalent of isnull in Netezza.
select t1.cust, isnull(t1.sales,0), t2.week
from daystable2 t2 left join salestable1 t1 on t1.week = t2.week
I think this will do the trick
SELECT week, cust, COALESCE(sales, 0)
FROM week_tbl a LEFT JOIN cust_table b
ON a.week = b.week

Select MAX for multiple criteria in a group

Apologies if this has been answered, I'm new enough that I didn't even know how to search:
I have one table:
Lot SKU Cost Date
1001-1 1001 .30 10-12-14
1001-2 1001 .33 10-19-14
1001-3 1001 .32 11-20-14
1002-1 1002 .45 10-12-14
1002-2 1002 .45 10-19-14
1002-3 1002 .44 12-01-14
1003-1 1003 .12 10-15-14
1003-2 1003 .13 10-19-14
1003-3 1003 .10 11-23-14
i need to sum the cost of the oldest row for each SKU.
expected outcome: (.30 + .45 + .12) = .87
is this possible through one query?
ANSI SQL support a function called row_number(), which can be very helpful for this type of query. The following is how you would use it in this case:
select sum(cost)
from (select t.*, row_number() over (partition by sku order by date) as seqnum
from table t
) t
where seqnum = 1;
This should work:
select sum(t.cost)
from some_table t
join ( select sku ,
min(some_datetime_column) oldest
from some_table
and some_datetime_column is not null
group by sku
) s on s.sku = t.sku
and s.oldest = t.some_datetime_column