Join Tables Where Absolute of Occurrences Equal to Absolute of Single Occurrence - sql

Problem: I am currently trying to join two tables in Access where the absolute value of the total of multiple occurrences of one field in one table is equal to the absolute value of the occurrence in another table.
Am I able to use the Abs function in the WHERE statement? Everything I saw involved the function being used in the SELECT statement. Do I need to create separate queries to get the absolute values? It would also work if I were to check to see if they balance out rather than getting the absolute value.
In one table, a certain value will repeat multiple times while it will only appear once in the other table. How can I get the absolute values of the totals in order to compare it to the single occurrence in the other table? Thanks!
Table 1
Reference
Amount
55555
$15
55555
$20
Table 2
Reference
Amount
55555
-$35
If these are equal or if they balance out, they should appear on a query. If these aren't equal but the reference number and a partial amount appears, they should appear on another query.

The matching query is relatively simple. Just aggregate and compare the values:
select t2.reference, t2.amount
from (select reference, sum(amount) as amount
from table2
group by reference
) as t2 inner join
(select reference, sum(amount) as amount
from table1
group by reference
) as t1
on t1.reference = t2.reference
where t2.amount + t1.amount = 0;
However, the non-matches are much trickier -- because presumably a reference could be missing from either table. And MS Access does not support full join. One method is:
select t2.reference, t2.amount, t1.amount
from (select reference, sum(amount) as amount
from table2
group by reference
) as t2 left join
(select reference, sum(amount) as amount
from table1
group by reference
) as t1
on t1.reference = t2.reference
where t2.amount + t1.amount <> 0 or t1.amount is null
union all
select t1.reference, null, sum(amount)
from table1 as t1
where not exists (select 1 from table2 as t2 where t2.reference = t1.reference)
group by t1.reference;

Aggregate data in Table1 and join to Table2.
Consider:
SELECT Table2.*, SumAmt FROM Table2
INNER JOIN (SELECT Reference, Sum(Amount) AS SumAmt FROM Table1 GROUP BY Reference) AS T
ON Table2.Reference = T.Reference
WHERE SumAmt = -Table2.Amount;

You can list if the amounts match or not, no Abs is needed:
Select
Table2.Reference,
Table2.Amount,
(T.Total = -Table2.Amount) As T1Match
From
Table2
Inner Join
(Select
Table1.Reference,
Sum(Table1.Amount) As Total
From
Table1
Group By
Table1.Reference) As T
On T.Reference On Table2.Reference

you can use sub-query as follows:
select t1.reference from
(select reference, sum(amount) as amount from table1 group by reference) t1
join table2 t2
on abs(t1.amount) = abs(t2.amount)

Related

sql - ignore duplicates while joining

I have two tables.
Table1 is 1591 rows. Table2 is 270 rows.
I want to fetch specific column data from Table2 based on some condition between them and also exclude duplicates which are in Table2. Which I mean to join the tables but get only one value from Table2 even if the condition has occurred more than time. The result should be exactly 1591 rows.
I tried to make Left,Right, Inner joins but the data comes more than or less 1591.
Example
Table1
type,address,name
40,blabla,Adam
20,blablabla,Joe
Table2
type,currency
40,usd
40,gbp
40,omr
Joining on 'type'
Result
type,address,name,currency
40,blabla,name,usd
20,blblbla,Joe,null
try this it has to work
select *
from
Table1 h
inner join
(select type,currency,ROW_NUMBER()over (partition by type order by
currency) as rn
from
Table2
) sr on
sr.type=h.type
and rn=1
Try this. It's standard SQL, therefore, it should work on your rdbms system.
select * from Table1 AS t
LEFT OUTER JOIN Table2 AS y ON t.[type] = y.[type] and y.currency IN (SELECT MAX(currency) FROM Table2 GROUP BY [type])
If you want to control which currency is joined, consider altering Table2 by adding a new column active/non active and modifying accordingly the JOIN clause.
You can use outer apply if it's supported.
select a.type, a.address, a.name, b.currency
from Table1 a
outer apply (
select top 1 currency
from Table2
where Table2.type = a.type
) b
I typical way to do this uses a correlated subquery. This guarantees that all rows in the first table are kept. And it generates an error if more than one row is returned from the second.
So:
select t1.*,
(select t2.currency
from table2 t2
where t2.type = t1.type
fetch first 1 row only
) as currency
from table1 t1;
You don't specify what database you are using, so this uses standard syntax for returning one row. Some databases use limit or top instead.

Sum Column in Joined Table and add as column SQL

So say I have two tables in Oracle SQL (not actually data but for ease should highlight my question)
Table1 that contains only Order_id and Order_quantity and Table2 that contains only Order_id and Order_price
Then I join them as follows
Select T1.Order_id,
T1.Order_quantity,
T2.Order_price,
T1.Order_quantity*T2.Order_price As "Order_amount",
Sum(Order_amount) As "Total_Sales"
from Table1 T1
inner join Table2 T2
on T1.Order_id = T2.Order_id
So essentially I want to have two extra columns, one as the product of columns from the two tables, and another as the sum of that column in my joined table(so every entry will be the same). However as you need to
SUM(variable_name) From Table_Name
Can I assign a variable name to my new table and then refer to that. I tried the following but I'm getting a SQL command not properly ended error
Select T1.Order_id,
T1.Order_quantity,
T2.Order_price,
T1.Order_quantity*T2.Order_price As "Order_amount",
Sum(Order_amount) from New_Table As "Total_Sales"
from (Table1 T1
inner join Table2 T2
on T1.Order_id = T2.Order_id) As New_Table
Thanks for any assistance, apologies as I have a pretty naive understanding of SQL at present
I think you just want a window function:
select T1.Order_id, T1.Order_quantity, T2.Order_price,
T1.Order_quantity*T2.Order_price As order_amount,
sum(T1.Order_quantity*T2.Order_price) over () As Total_Sales
from Table1 T1 inner join
Table2 T2
on T1.Order_id = T2.Order_id
You cannot re-use the alias order_amount in the select. You need to repeat the expression -- or use a subquery or CTE to define it.
If your DBMS doesn't have a window function supports then you can use subquery instead
select order_id, Order_quantity,
(select t1.Order_quantity * t2.Order_price
from table2 t2
where t2.Order_id = t1.Order_id) as Order_amount,
(select sum(t1.Order_quantity * t2.Order_price)
from table2 t2
where t2.Order_id = t1.Order_id) as Total_Sales
from table1 t1;

Joining tables + SUM & GROUP BY function

I'm struggling in joining tables together with SUM and GROUP BY function. The query below works fine:
select ID, sum(amount)
from table1
group by ID
having sum(amount) between 1000 and 10000
As table1 only includes customer ID, I also need to join table CUSTOMERS, which contain customer name (column NAME). Following query will not work for me anymore:
select ID, name, sum(amount)
from table1
left join customers on table1.ID = customers.ID2
group by ID
having sum(amount) between 1000 and 10000
Ditching SUM and GROUP BY functionality does "fix" the issue as also column NAME will be available in the result, however I still need to sum and group the AMOUNT based on ID. How should I join the other table in this case to also present field NAME from table CUSTOMERS?
Column NAME or expression in SELECT list not valid'
is currently given as error message.
It needs to be in the group by:
select t1.ID, c.name, sum(t1.amount)
from table1 t1 left join
customers c
on t1.ID = c.ID2
group by t1.ID, c.name;
Note the use of table aliases.
Add "name" in group by clause
select table1.ID, customers.name, sum(table1.amount) amount
from table1,customers on table1.ID = customers.ID2
group by table1.ID,customers.name
try it
select t.ID, c.name, sum(t.amount)
from table1 t
left join customers c on table1.ID = customers.ID2
group by t.ID, c.name
having sum(t.amount) between 1000 and 10000
or without having depends on your requirement

Counts for distinct values in different tables where columns are common to separate tables

I have no idea if that title conveys what I want it to.
I have two tables containing phone records (one for each account) and I'd like to get call counts for the numbers that are common to each account. In other words:
Table 1
Number ...
8675309
8675309
8675310
8675310
8675312
Table 2
Number ...
8675309
8675309
8675309
8675310
8675311
Querying with something like:
SELECT DISTINCT table1.number, COUNT(table1.number), COUNT(table2.number) FROM table1, table2 WHERE table1.number = table2.number GROUP BY table1.number
would hopefully produce:
8675309|2|3
8675310|2|1
Instead, it currently produces something like:
8675309|6|6
8675310|2|2
It appears to be multiplying the count from each table. Presumably, this is because I'm not joining the tables the way I should for this goal. Or because by the time I ask for COUNT(table1.number) the tables have already been joined in some multiplicative way. Should I not be doing a JOIN and instead something that would read like: "where table2.number CONTAINS(table1.number)"?
Any tips?
One way is with subqueries:
SELECT t1.number, t1.table1Count, t2.table2Count
from (select number, count(*) table1Count
from table1
group by number) t1
inner join (select number, count(*) table2Count
from table2
group by number) t2
on t2.number = t1.number
This assumes that you only want to list numbers that appear in both tables. If you want to list all numbers that appear in one table and optionally the other, you'd use a left or right outer join; if you wanted all numbers that appeared in either or both tables, you'd use a full outer join.
Another and potentially more efficient way requires the presence of a single column that uniquely identifies each row in each table:
SELECT
t1.number
,count(distinct t1.PrimaryKeyValue) table1Count
,count(distinct t2.PrimaryKeyValue) table2Count
from table1 t1
inner join table2 t2
on t2.number = t1.number
group by t1.number
This makes the same assumptions as before, and can also be adjusted modified via outer joins.
One way is to use a couple of derived tables to compute your counts separately and then join them to produce your final summary:
select t1.number, t1.count1, t2.count2
from (select number, count(number) as count1 from table1 group by number) as t1
join (select number, count(number) as count2 from table2 group by number) as t2
on t1.number = t2.number
There are probably other ways but that should work and it is the first thing that came to mind.
You're getting your "multiplicative" effect pretty much for the reasons you suspect. If you have this:
table1(id,x) table2(id,x)
------------ ------------
1, a 4, a
2, a 5, a
3, b 6, b
Then joining them on x will give you this:
1,a, 4,a
1,a, 5,a
2,a, 4,a
2,a, 5,a
...
Usually you could use a GROUP BY to sort out the duplicates but you can't do that because it would mess up your per-table counts.
Try this:
select tab1.number,tab1.num1,tab2.num2
from
(SELECT number, COUNT(number) as num1 from table1 group by number) as tab1
left join
(SELECT number, COUNT(number) as num2 from table2 group by number) as tab2
on tab1.number = tab2.number

JOIN without double values

I've got query
SELECT frst.Date,t1.Value
from
[ArchiveAnalog] frst
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 1) t1
ON t1.Date = frst.Date
order by frst.Date
but Join inserts values second time (not group with a main node)
if I do GROUP BY frst.Date , I've got error that I can't use t1 Value with it.
How can I make this JOIN without adding additional rows ?
Martin I want to show full Date and Value only if ID = 1 , also then I want to add t2 value column etc like here :
SELECT frst.Date,t1.Value,t2.Value
from
[ArchiveAnalog] frst
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 1) t1
ON t1.Date = frst.Date
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 2) t2
ON frst.Date = t2.Date
here I have x2 additional rows :S with doubling values, so I need to group them all with a some way.
You either need DISTINCT in the main query (if there's up to one row in t1 that you need), or GROUP BY. If you use GROUP BY, you need to aggregate t1.Value (e.g. sum, concatenate etc.).
Does this do what you need?
SELECT Date ,
MAX(CASE WHEN ID=1 THEN Value END) AS val1,
MAX(CASE WHEN ID=2 THEN Value END) AS val2
FROM [ArchiveAnalog]
WHERE ID IN (1,2) /*<-- Not sure if you need this line without seeing your data*/
GROUP BY Date