Table A1 Table B1
A --100 id =1 A --100 id=1
B -- 100 id =2 A -100 id=1
C -- 200 id=3 A - 100 id =1
Need to sum all values from two tables where id =1.
select (SUM(A1.A) + SUM(nvl(B1.A,0))) SUM from A1 a, B1 b where a.id='1' AND b.id='1';
I am getting sum as 600 but it should be 400
Something like this should work.
SELECT id, SUM(A) as Totals FROM
(
SELECT id, A FROM A1
UNION ALL
SELECT id, A FROM B1
) AS tblData
GROUP BY id
You can use:
SELECT COALESCE((SELECT SUM(A) FROM A1 WHERE ID = 1), 0) +
COALESCE((SELECT SUM(A) FROM B1 WHERE ID = 1), 0)
you can do by this way
select sum(A) as total
from
(
select A
from A1 where id = 1
union all
select A
from B1 where id = 1
) t
Here is a method that doesn't use subqueries (although I am not recommending it):
select coalesce(sum(a.a), 0) + coalesce(sum(b.b), 0)
from a full outer join
b
on 1 = 0
where a.id = 1 or b.id = 1;
You used CROSS JOIN ( Cartesian product ) so you get 600..
You can try this to use UNION combine two table.
SELECT SUM(T.Totle)
FROM
(
select SUM(A1.A) Totle from A1 a where a.id='1'
UNION ALL
select SUM(B1.A) Totle from B1 b where b.id='1'
) T
SQLFiddle
Related
I am unable to generate a looping kind of behaviour in a SQL query.
I am having two tables:
Table A
Id Brand Prod_Id Alt_Prod_Id
1 A 2 5
2 B 3 9
3 C 5 9
Table B
Id Prod_Id Rate
1 2 5
2 3 9
2 5 7
2 9 9
Rate in Table B needs to be looked up for each brands Prod_ID & Alt_Prod_Id & select the least value between 2 found value
The expected result / output is:
Brand Min_Prod_Val
A 5
B 9
C 7
Can this be done in a query?
Thanks!
You could join tableb twice (once for prod_id, another for alt_prod_id), and then select the smallest rate:
select
a.brand,
least(b1.rate, b2.rate) min_prod_val
from tablea a
inner join tableb b1 on b1.prod_id = a.prod_id
inner join tableb b2 on b2.prod_id = a.alt_prod_id
It is unclear which database you are using. If that's SQL Server: it does not support least(), so you need a case expression:
case when b1.rate < b2.rate then b1.rate else b2.rate end min_prod_val
You can use a single join and GROUP BY the brand:
SELECT a.Brand,
MIN( b.rate ) AS min_prod_val
FROM TableA A
INNER JOIN TableB b
ON ( b.prod_id IN ( a.prod_id, a.alt_prod_id ) )
GROUP BY a.Brand
Or you can use a correlated sub-query:
SELECT a.Brand,
(
SELECT MIN( rate )
FROM TableB b
WHERE b.prod_id IN ( a.prod_id, a.alt_prod_id )
) AS min_prod_val
FROM TableA A
db<>fiddle
let me explain what i need, i have 2 table named A and B. B is sub table for A.
Here is Schema:
------------------------
Table B:
itemId version qty AId
44 1 1 200
44 1 2 201
44 2 2 200
------------------------
Table A:
id tId
200 100
201 100
------------------------
and here is what i need: i need sum of all latest version qty that have same tId.
here is my query:
select sum(qty) as sum from B
left join A on A.id=B.AId
where itemId=44 and tId=100 and
version=(select max(version) from B where itemId=44 and tId=100)
the result get wrong when one item got version 2 and version 1 ignored.
thanks.
EDIT:
what exactly i need is:
itemId version qty AId
44 2 2 200
44 1 2 201
And Result of Sum(qty) must be 4, because they have same tId and they have Max version in each AId.
Use window function.
select itemid, version, qty, aid
from (
select *, max(version) over (partition by AId) as latestVersion
from B
) as B
where version = latestVersion
to sum up
select tId, SUM(qty) AS qty_sum
from (
select *, max(version) over (partition by AId) as latestVersion
from B
) as B
join A on B.AId = A.id
where version = latestVersion
group by tId
Working solution
select b.* from B as b
inner join
(select AID,itemId,Max(version) as mVersion from B
group by AID,itemID) d
on b.AID = d.AID and b.itemID = d.itemID and b.Version = d.mVersion
inner join A as a
on B.AID = a.id
where b.itemID = 44 --apply if you need
result
itemid version qty aid
44 2 2 200
44 1 2 201
this will give you result as you sum of quantity
select itemID,sum(qty) from (
select b.* from B as b
inner join
(select AID,itemId,Max(version) as mVersion from B
group by AID,itemID) d
on b.AID = d.AID and b.itemID = d.itemID and b.Version = d.mVersion
inner join A as a
on B.AID = a.id
where b.itemID = 44 --apply if you need
) e group by itemID
result
itemid sum
44 4
Try This one
DECLARE #TA Table (id int,tid int)
DECLARE #TB Table (itemid int, version int,qty int,AID int)
INSERT INTO #TA
SELECT 200, 100
UNION ALL
SELECT 201, 100
INSERT INTO #TB
SELECT 44,1,1,201
UNION ALL
SELECT 44,1,2,200
UNION ALL
SELECT 44,2,3,200
UNION ALL
SELECT 44,2,5,201
DECLARE #tid int
SET #tid = 100
SELECT XB.* FROM #Tb XB INNER JOIN
(SELECT Version,Max(AID) Aid FROM #TA A INNER JOIN #TB B ON A.id = B.AID AND tid = #tid Group By Version) X
ON X.version = XB.version and XB.AID = X.Aid
i think this query help you to solve your problem
SELECT itemId, version, qty , AId FROM (
SELECT itemId, version, qty , AId FROM b
LEFT JOIN a ON (b.aid = a.id)
) temp
WHERE version = (SELECT MAX(version) FROM b WHERE b.aid = temp.aid)
and temp.tid = 100 and temp.itemId = 44
SELECT B.*
FROM B
INNER JOIN
(SELECT Aid,MAX(version) AS version FROM B WHERE itemId=44 GROUP BY AId) AS B1
ON B.Aid=B1.Aid
AND B.version=B1.version
INNER JOIN
(SELECT * FROM A WHERE tId=100) AS A
ON A.id=B.Aid
Order BY B.aid
For Sum of qty
SELECT SUM(B.qty)
FROM B
INNER JOIN
(SELECT Aid,MAX(version) AS version FROM B WHERE itemId=44 GROUP BY AId) AS B1
ON B.Aid=B1.Aid AND B.version=B1.version
INNER JOIN
(SELECT * FROM A WHERE tId=100) AS A
ON A.id=B.Aid
GROUP BY A.tid
Output
itemid version qty aid
44 2 2 200
44 1 2 201
Demo
http://sqlfiddle.com/#!17/092dd/5
The most efficient solution greatest-n-per-group problems in Postgres are typically using the (proprietary) operator distinct on ()
So to get the latest version for each a.id, you can use:
select distinct on (a.id) b.*
from a
join b on a.id = b.aid
order by a.id, b.version desc;
The above returns:
itemid | version | qty | aid
-------+---------+-----+----
44 | 2 | 2 | 200
44 | 1 | 2 | 201
You can then sum over the result:
select sum(qty)
from (
select distinct on (a.id) b.qty
from a
join b on a.id = b.aid
order by a.id, b.version desc
) t;
Note that normally an order by in a derived table is useless, but in this case it's needed because otherwise distinct on () wouldn't work.
Online example: http://rextester.com/DRHK19268
I have following table
ID Name Stage
1 A 1
1 B 2
1 C 3
1 A 4
1 N 5
1 B 6
1 J 7
1 C 8
1 D 9
1 E 10
I need output as below with parameters A and N need to select closest rows where difference between stage is smallest
ID Name Stage
1 A 4
1 N 5
I need to select rows where difference between stage is smallest
This query can make use of an index on (name, stage) efficiently:
WITH cte AS (
SELECT TOP 1
a.id AS a_id, a.name AS a_name, a.stage AS a_stage
, n.id AS n_id, n.name AS n_name, n.stage AS n_stage
FROM tbl a
CROSS APPLY (
SELECT TOP 1 *, stage - a.stage AS diff
FROM tbl
WHERE name = 'N'
AND stage >= a.stage
ORDER BY stage
UNION ALL
SELECT TOP 1 *, a.stage - stage AS diff
FROM tbl
WHERE name = 'N'
AND stage < a.stage
ORDER BY stage DESC
) n
WHERE a.name = 'A'
ORDER BY diff
)
SELECT a_id AS id, a_name AS name, a_stage AS stage FROM cte
UNION ALL
SELECT n_id, n_name, n_stage FROM cte;
SQL Server uses CROSS APPLY in place of standard-SQL LATERAL.
In case of ties (equal difference) the winner is arbitrary, unless you add more ORDER BY expressions as tiebreaker.
dbfiddle here
This solution works, if u know the minimum difference is always 1
SELECT *
FROM myTable as a
CROSS JOIN myTable as b
where a.stage-b.stage=1;
a.ID a.Name a.Stage b.ID b.Name b.Stage
1 A 4 1 N 5
Or simpler if u don't know the minimum
SELECT *
FROM myTable as a
CROSS JOIN myTable as b
where a.stage-b.stage in (SELECT min (a.stage-b.stage)
FROM myTable as a
CROSS JOIN myTable as b)
I have a table called Fruit which has two columns (id,cost) and I want to select id and cost, and find all duplicate rows where the cost is the same but the id is different. How can I write this query?
I write this query
SELECT id,cost
From Fruit a
WHERE (SELECT COUNT(*)
FROM Fruit b
WHERE a.cost = b.cost
) > 1
This works but only give me the rows where the cost is the same but the id might be same as well, I only want results where the cost is the same but id is different
This is what you need:
SELECT DISTINCT F1.*
FROM Fruit F1
INNER JOIN Fruit F2 ON F1.id <> F2.id AND F1.cost = F2.cost
If you want repeated id-cost pairs to be listed too, just remove the DISTINCT.
You can add a simple condition where id are not equal.
SELECT id,cost From Fruit a WHERE (SELECT COUNT(*) FROM Fruit b WHERE a.cost = b.cost and a.id <> b.id ) > 1
Here <> is operator for not equal.
I hope it will help you :)
you could select all the rows with cost duplicated using a group by and having ccount(*) >1
and for this get all the row that match
select a.id, a.cost
from Fruit a
where cost in ( select b.cost
from fruit b
group by b.cost
having count(*) > 1
)
for avoid duplicated result you can add distinct
select distinct a.id, a.cost
from Fruit a
where cost in ( select b.cost
from fruit b
group by b.cost
having count(*) > 1
)
You can add a simple condition where id are not equal.
SELECT id,cost From Fruit a WHERE (SELECT COUNT(*) FROM Fruit b WHERE a.cost = b.cost and a.id <> b.id ) > 1
Here <> is the operator Of not equal in sql.
This works. Ran it in SQL Server because Oracle is broken on Fiddle, but should work on either system.
MS SQL Server 2014 Schema Setup:
CREATE TABLE ab
([id] int, [cost] int)
;
INSERT INTO ab
([id], [cost])
VALUES
(1, 5),
(2, 5),
(3, 15),
(3, 15),
(4, 24),
(5, 68),
(6, 13),
(7, 3)
;
Query 1:
with a1 as (
SELECT id
,cost
,rank () over (partition by cost order by id) dup
From ab
)
select * from a1 where dup > 1
Results:
| id | cost | dup |
|----|------|-----|
| 2 | 5 | 2 |
And then to return all values where there was a duplicate cost:
with a1 as (
SELECT id
,cost
,rank () over (partition by cost order by id) dup
From ab
)
,a2 as ( select * from a1 where dup > 1)
select * from ab
join a2 on ab.cost = a2.cost
Suppose we have the database:
-----------
| A -|- B |
|----|----|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
-----------
Where A and B is the primary key. Suppose we want to get all As that contain the elements in B of 1 and 2.
SELECT A FROM Table WHERE B = 1 AND B = 2;
The above fails because it never holds true as the query is only for a single record.
SELECT A FROM Table WHERE B = 1 OR B = 2;
Works but erroneously includes the primary key value 2, which only maps to 1 in B, and not both 1 and 2 in B.
GROUP BY solution, return all a's that have more than 1 different b value in (1,2):
select a from table
where b in (1,2)
group by a
having count(distinct b) > 1
Or, JOIN solution:
select distinct a
from (select a from table where b = 1) t1
join (select a from table where b = 2) t2
on t1.a = t2.a
Or an INTERSECT solution:
select a from table where b = 1
intersect
select a from table where b = 2
Edit:
GROUP BY query that perhaps is faster then the HAVING count distinct version:
select a from table
where b in (1,2)
group by a
having max(b) <> min(b)
You can use the group by method from jarlh or make a Join with a 'distinct':
select distinct a
from (select a from table where b = 1) t1
join (select a from table where b = 2) t2
on t1.a = t2.a
Something like this (assuming that you need to filter by the specific IDs in B.
SELECT DISTINCT A
FROM Table AS T
WHERE EXISTS (SELECT 1 from Table WHERE Table.A = T.A and B = 1)
AND EXISTS (SELECT 1 from Table WHERE Table.A = T.A and B = 2)
Try this
SELECT A
FROM Table
WHERE EXISTS (
SELECT 1
FROM Table t1
WHERE t1.A = Table.A
AND t1.B = 1
)
AND EXISTS (
SELECT 1
FROM Table t2
WHERE t2.A = Table.A
AND t2.B = 2
)
A cannot be the primary key here, since the column contains duplicates.
One possible solution:
SELECT * FROM (SELECT A, group_concat(B, ',') AS C FROM tab GROUP BY A) s WHERE s.C = "1,2";