I have two tables both with 2 columns (Name[string], value[integer])
I am trying to join the two to display the differences between the sum(value) of each Name. e.g.
Table1(t1):
N1 2
N1 3
N2 4
N3 5
Table(t2):
N1 1
N2 1
N2 1
Result should look like:
N1 4 (5-1)
N2 2 (4-2)
N3 5 (5-0)
We want to assume 0 if N is missing from either one of the tables
I only know how to do the join if the names exist in both table but i do not know how to handle replacing empty results with value of 0 if name is missing in either table.
My current query:
select t1.name, t2.name, t1.Sum-t2.Sum as "Diff"
from (select t1.name, sum(t1.value) as Sum from t1 group by t1.name) t1
inner join
(select t2.name, sum(t2.value) as Sum from t2 group by t2.name) t2
on t1.name = t2.name
The result ignores N3 because N3 is missing from t1.
thank you
You can aggregate both tables using CTEs (Common Table Expressions) and then join them using a FULL OUTER JOIN, as in:
with
l as (
select name, sum(value) as total
from table1
group by name
),
r as (
select name, sum(value) as total
from table2
group by name
)
select
coalesce(l.name, r.name) as name,
coalesce(l.total, 0) - coalesce(r.total, 0) as difference
from l
full outer join r on l.name = r.name
order by coalesce(l.name, r.name)
Use FULL OUTER JOIN and ISNULL
SELECT ISNULL(x.name, y.name) as Name,
ISNULL(x.sumValues, 0) - ISNULL(y.sumValues, 0) as ValueDiff
FROM
(SELECT name, SUM(value) AS sumValues FROM t1 GROUP BY name) x
FULL OUTER JOIN
(SELECT name, SUM(value) AS sumValues FROM t2 GROUP BY name) y
ON x.name = y.name;
A pretty simple method is union all and aggregation:
select name, sum(value)
from ((select name, value
from t1
) union all
(select name, -value
from t2
)
) t
group by name;
The join is a bit messy because it can result in duplicated and missing values, unless done very carefully.
this will work:
input:
create table t1 (name varchar(20),value number);
create table t2 (name varchar(20),value number);
//do inserts
select name1,nvl(sum1-sum2,sum1) from(select sum(t1.value) as sum1,t1.name name1 from t1 group by t1.name)
,(select sum(t2.value) as sum2,t2.name name2 from t2 group by t2.name) where name1=name2(+);
output:
N1 4
N2 2
N3 5
Related
I am trying to select multiple values from two tables but i want to group by single value. I have tried using max(value) in select but max is returning the greatest one and not the exact one.
Here are my tables
The result i need is something like this
Result : HeadQuarterId - A, PropertyName - Name1, Amount - 102
HeadQuarterId - B, PropertyName - Name5, Amount - 30
Here is my query
SELECT Headquarterid,Max(PropertyName),sum(Amount)
FROM Table1 A LEFT OUTER JOIN Table2 B
ON A.Propetyid = B.PropertyId
GROUP BY Headquarterid
Here i have used Left Outer Join so that i will get all the data from left table even it is not available in right table.
Also i cannot use A.HeadquarterID = A.PropertyId in where condition since i have other dependency in that table. Please suggest someother way to achieve this result.
I think I understand. You want the headquarters with the maximum value, which happens to be A. If so:
select t1.*, sum(t2.amount) over () as total
from t1 left join
t2
on t2.PropertyId = t1.PropertyId
order by t2.amount desc
fetch first 1 row only;
Note: Not all databases support fetch first. It might be spelled limit or use select top (1) for instance.
I would recommend to get the headquartename per ID in a cte / subquery, then join it again to T1 and left join T1 to T2 in a second cte / subquery. This way you can calculate your sums basing on a single group:
WITH cte AS(
SELECT ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY CASE WHEN t1.ID = t1.PROPERTYID THEN 0 ELSE 1 END) rn, t1.ID, t1.Name
FROM t1
),
cte2 AS(
SELECT c.name cName, t1.*, t2.Value
FROM t1
INNER JOIN cte c ON c.ID = t1.ID AND c.rn = 1
LEFT JOIN t2 ON t1.Propertyid = t2.propertyid
)
SELECT c2.id, c2.cname, sum(c2.value) value
FROM cte2 c2
GROUP BY c2.id, c2.cname
See SQLFiddle for details: http://sqlfiddle.com/#!18/8bf66/13/2
Of course you can build the first cte without the row_number only by using the WHERE ID = PROPERTYID - matter of taste I'd say...
As per your sample data you want window function :
select distinct t1.HeadQuarterId,
max(t1.PropertyName) over (partition by t1.HeadQuarterId) as PropertyName,
sum(t2.amount) over (partition by t1.HeadQuarterId) as amount
from t1 left join
t2
on t2.PropertyId = t1.PropertyId;
This provided the result i expected.
SELECT HQTRS1 AS headId,Max(LLORD1) AS headName, sum(Amount) AS amount
FROM
(SELECT DISTINCT HeadQuarterId AS HQTRS1, PropertyName AS LLORD1 FROM Table_1 WHERE HeadQuarterId = PropertyId) AS temp
INNER JOIN Table_1 AS A ON A.HeadQuarterId = temp.HQTRS1
LEFT OUTER JOIN Table_2 B
ON B.PropertyId = A.PropertyId
GROUP BY HQTRS1
I have a table t2 with field Col & a,b,c,d,e as records. I'm trying to get an output like:
r1 0 1
1 b a
2 d c
4 e
when i use the below query i get an error: Syntax error in the expresion (((Select Count(b.Col)+1 from t2 as b where a.col>b.col)+1)\2
Transform
first(col) as col1
Select ((Select Count(b.Col)+1 from t2 as b where a.col>b.col)+1)\2 as r1
From t2 as a
Group by (((Select Count(b.Col)+1 from t2 as b where a.col>b.col)+1)\2)
Pivot
(Select Count(b.Col)+1 from t2 as b where a.col>b.col) MOD 2
I don't think so. Just use a subquery:
select r1
from (select a.*,
(Select Count(b.Col)+1 from t2 as b where a.col>b.col)+1)\2 as r1
from t2 as a
) as a1
group by r1;
Or, because you are only selecting distinct values, use select distinct rather than group by in the original query.
How to find the non matching records from both the tables?
You can use NOT EXISTS to find out the not matching Id from both the tables and can combine it by UNION ALL.
Query
SELECT t1.[Id] FROM [table-1] t1
WHERE NOT EXISTS(
SELECT 1 FROM [table-2] t2
WHERE t1.[Id] = t2.[Id]
)
UNION ALL
SELECT t2.[Id] FROM [table-2] t2
WHERE NOT EXISTS(
SELECT 1 FROM [table-1] t1
WHERE t1.[Id] = t2.[Id]
);
Demo for reference
Another way with TOP 1 WITH TIES and COUNT OVER:
SELECT TOP 1 WITH TIES *
FROM (
SELECT *
FROM [table-1]
UNION ALL
SELECT *
FROM [table-2]
) u
ORDER BY COUNT(*) OVER (PARTITION BY Id ORDER BY Id)
Output:
Id name
D ...
E ...
F ...
G ...
H ...
I ...
J ...
K ...
COUNT(*) OVER (PARTITION BY Id ORDER BY Id) Gives 1 to unique row and >1 if there are duplicated Ids. If you put that to ORDER BY and add TOP 1 WITH TIES - that will left only Ids with minimal count.
Another way with FULL OUTER JOIN:
SELECT COALESCE(Id1,Id2) Id,
COALESCE(name1,name2) name
FROM (
SELECT t1.Id Id1,
t1.[name] name1,
t2.Id Id2,
t2.[name] name2
FROM [table-1] t1
FULL OUTER JOIN [table-2] t2
ON t1.Id = t2.Id
WHERE t1.Id IS NULL OR t2.ID IS NULL
) as t
Same output (with another order)
There are 2 tables with data as below. The column 'ID' is the available in both tables. can someone please help me how do i get the desired output.
Table 1:
ID IND
101 Y
102 N
Table 2:
ID CD
101 A
101 B
101 C
101 D
102 A
Desired output:
ID CD IND
101 A Y
101 B
101 C
101 D
102 A N
What you have here is a join where you want to display the value of ind only on the first cd of each id. You can do this with the row_number() window function in a case expression:
SELECT t1.id, t2.cd, CASE rn WHEN 1 THEN t1.ind ELSE NULL END AS ind
FROM table1 t1
JOIN (SELECT id, cd, ROW_NUMBER() OVER (PARTITION BY ind ORDER BY cd ASC) AS rn
FROM table2) t2 ON t1.id = t2.id
This should do the trick.
SELECT table1.ID, table2.CD, table1.IND
FROM table1
INNER JOIN table2
ON table1.ID = table2.ID;
I would normally expect that if you had a table with a relationship in the ID column that you would want to do a simple inner join: http://sqlfiddle.com/#!4/e8e41/5
select t1.id, t2.cd, t1.ind
from t1
inner join t2
on t2.id = t1.id
However, that wouldn't give you the result you specified. Your IND field would be populated for each row.
Perhaps you're looking to join only where cd = 'A'. I don't know the point of that, but you could do something like this: http://sqlfiddle.com/#!4/e8e41/12
select t2.id, t2.cd, coalesce(t1.ind,' ') as ind
from t2
left join t1
on t2.id = t1.id
and t2.cd = 'A'
order by id, cd
Or perhaps you're looking to associate the ind with the first cd of each id. In that case, something like this (using a common table expression) might work for you: http://sqlfiddle.com/#!4/e8e41/20
with cte as (
select id, cd, row_number() over (partition by id order by cd) as rn
from t2
)
select t1.id, cte.cd, case when rn = 1 then t1.ind else ' ' end as ind
from t1
inner join cte
on t1.id = cte.id
Some data would be organized thusly:
ID DATE COUNT1 COUNT2
A 20120101 1 2
A 20120201 2 2
B 20120101 3 0
C 20111201 1 0
C 20120301 2 2
Another table has ID NAME
A MYNAME
.... etc
i want to return a table of
ID NAME COUNT COUNT2
for the most recent available piece of data, i.e. the january count for A is not included
i know I need to use HAVING, INNER JOIN, and GROUP BY but every iteration I can come up with has an error.
If you only want rows with the date equal to the global maximum date, just use a subquery:
select ID,DATE,COUNT1,COUNT2
from table
where DATE=(select max(DATE) from table);
If you want the maximum date per ID, then you can use a self join:
select ID,MAX_DATE,COUNT1,COUNT2
from(
select ID,max(DATE) as MAX_DATE
from table
group by ID
)a
join(
select ID,DATE,COUNT1,COUNT2
from table
)b
on (a.ID=b.ID and a.MAX_DATE=b.DATE);
Not necessarily. This should also work:
select t1.id, t2.name, t1,count1, t1.count2
from table_1 t1 join table_2 t2 on (t1.id = t2.id)
where not exists (
select 1
from table_1 t3
where t1.id = t3.id
and t1.date < t3.date)
order by 1;
You'll need a correlated subquery:
SELECT Id, Name, Count1, Count2
FROM CountsTable AS T1 INNER JOIN NamesTable ON T1.Id=NamesTable.Id
WHERE CountsTable.Date = (
SELECT Max(Date) From CountsTable AS T2 WHERE T1.Id=T2.Id
)