MS access multiple query left join - sql

I am creating a table in MS ACCESS using multiple sub query in a way such that 1st table contains the whole set and remaining are based on some another condition - here is my code
SELECT a.id,
a.cnt AS Total_Count,
b.cnt AS Income_Count
INTO data
FROM (SELECT id,
Count(*) AS Cnt
FROM test
GROUP BY id) AS a
LEFT JOIN (SELECT id,
Count(*) AS Cnt
FROM test
WHERE inc > 25
GROUP BY id) AS b
ON a.id = b.id;
It works fine. But when I am putting another sub query its not working
SELECT a.id,
a.cnt AS Total_Count,
b,
b.cnt AS Income_Count,
c.cnt AS EXP_Count
INTO data
FROM (SELECT id,
Count(*) AS Cnt
FROM test
GROUP BY id) AS a
LEFT JOIN (SELECT id,
Count(*) AS Cnt
FROM test
WHERE inc > 25
GROUP BY id) AS b
ON a.id = b.id
LEFT JOIN (SELECT id,
Count(*) AS Cnt
FROM test
WHERE exp > 25
GROUP BY id) AS c
ON a.id = c.id;
Can you please help me on this.

SELECT a.id,
a.cnt AS Total_Count,
b, <----------------- What is this? b is an alias for a table, not a field
b.cnt AS Income_Count,
c.cnt AS EXP_Count
INTO data
FROM (SELECT id,
Count(*) AS Cnt
FROM test
GROUP BY id) AS a
LEFT JOIN (SELECT id,
Count(*) AS Cnt
FROM test
WHERE inc > 25
GROUP BY id) AS b
ON a.id = b.id
LEFT JOIN (SELECT id,
Count(*) AS Cnt
FROM test
WHERE exp > 25
GROUP BY id) AS c
ON a.id = c.id;
Remove the 'b' or replace it with an actual field. Be careful, if you use b.id then you will run into issues with trying to create two columns with the same name 'id' you will have to change the name of one of them. I ran this on a sql server an it worked fine without the 'b'.

Related

Set contains other set in SQL

Is anybody to know how to find sets which contain all sets of other sets
table
id elem
1 A
1 C
2 B
2 D
2 A
2 C
3 A
3 E
3 F
4 F
4 F
I want to get this:
id
2
3
In that case id 2 contains (A,C) - all set of id 1
and id 3 contains (F) - all set of id 4
In my query I need to get all id which contains all set (all elements) at least one id.
I will be very grateful. Thank you.
I didn't have much to go off of for this one, but it was interested so I guessed. I'm using SQL Server
Follow along in Rextester
I submit the answer which has nested selects, then I follow through on the step by step logic to clarify what's going on:
Build a quick table
CREATE TABLE a (id int, t varchar(10))
INSERT INTO a (id, t)
VALUES (1,'A'),(1,'B'),(1,'B'),(1,'B'),(2,'A')
,(2,'B'),(2,'C'),(3,'C'),(3,'D'),(4,'A'),(5,'P');
Here is the solution:
select distinct p_id supersets from
(
select e.p_id, e.c_id, count(*) matches from (
select distinct c.id p_id, c.t p_t, d.id c_id, d.t c_t from a c
inner join a d on c.t = d.t and c.id <> d.id) e
group by e.p_id, e.c_id) sup
inner join
(select id, count(distinct t) reqs from a group by id) sub
on sub.id = sup.c_id and sup.matches = sub.reqs;
Here are the logical steps broken out to help explain why I'm doing what I'm doing:
--Step1
--Create a list of matches between (distinct) values where IDs are not the same
select distinct c.id p_id, c.t p_t, d.id c_id, d.t c_t from a c
inner join a d on c.t = d.t and c.id <> d.id;
--Step2
--Create a unique list of parent IDs and their child IDs and the # of distinct matches
--For example 2 has 2 matches with 1 and vice versa
select e.p_id, e.c_id, count(*) matches from (
select distinct c.id p_id, c.t p_t, d.id c_id, d.t c_t from a c
inner join a d on c.t = d.t and c.id <> d.id) e
group by e.p_id, e.c_id;
--Step2a
--Create a sub query to see how many distinct values are in each "Set"
select id, count(distinct t) reqs from a group by id;
Now we put it all together in the join (above, first) to make sure the total # of matches from Parent to Child make up 100% of the child values ie(is a super set)
I think the following does what you want:
select t1.id
from t t1 join
(select t.*, count(*) over (partition by id) as cnt
from t
) t2
on t1.elem = t2.elem and t1.id <> t2.id
group by t1.id, t2.id, t2.cnt
having count(*) = cnt;
This matches each id to each other id based on the elements. If the number of matches equals the count in the second set, then all match -- and you have a superset.
I notice that you have duplicate elements. Let's handle this with a CTE:
with t as (
select distinct id, elem
from t
)
select t1.id
from t t1 join
(select t.*, count(*) over (partition by id) as cnt
from t
) t2
on t1.elem = t2.elem and t1.id <> t2.id
group by t1.id, t2.id, t2.cnt
having count(*) = cnt;

Postgres find tuples by WHERE and COUNT from other table

I have two tables
table a
id
title
year
table b
id
a.id references a(id)
I want to get title, year and count() for all tuples with max(year). I just can't get this to work.
I can do them separate, but whenever i add a WHERE clause it fails.
select title, year, count(*)
from a inner join b on a.id = b.a_id
group by title, year
Something like this would give me list with title year and count. If I try to add a WHERE clause
select title, year, count(*)
from a inner join b on a.id = b.a_id
where year = (select max(year) from a)
group by title, year
Here I get no tuple. I think I almost understand why, but I can't manage to solve it.
Hope someone understands me and can help!
how about this?
WITH a_max_years AS (
SELECT id
FROM a
WHERE year = (SELECT max(year) FROM a)
)
SELECT a.title, a.year, count(1)
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN a_max_years.id = a.id
GROUP BY b.a_id;
or:
WITH b_counts AS (
SELECT a_id, count(1) as cnt
FROM b
GROUP BY a_id
)
SELECT a.title, a.year, b_counts.cnt
FROM a
INNER JOIN b_counts ON b_counts.a_id = a.id
WHERE a.year = (SELECT max(year) FROM a);
you could also write them as INNER JOIN (SELECT ...) a_max_years, but WITH is more readable

SQL Subquery to get first record

I need to execute a query something like below.
SELECT TO_CHAR(ROWNUM),
A.Name,
B.Order,
(SELECT * FROM (
SELECT ROUND(LAST_ORDER_AMOUNT,5) FROM ORDERS WHERE ID=A.id AND REQUEST_LEVEL='N' ORDER BY O_DATE DESC)
WHERE ROWNUM =1) AS AMOUNT
FROM Table1 A LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
But this gives me A.ID is invalid error in oracle. I need to get the first record from inner query as it will return multiple records.
Can someone please let me know how can i bind these tables to achieve my goal.
Thank you in advance.
You can rewrite subquery using WITH clause, not exactly sure on syntax but should be something like following.
WITH AmountQuery
AS (
SELECT ID
,ROUND(LAST_ORDER_AMOUNT, 5) AS AmountValue
,ROW_NUMBER() OVER ( ORDER BY O_DATE DESC ) AS RN
FROM ORDERS
WHERE REQUEST_LEVEL = 'N'
)
SELECT TO_CHAR(ROWNUM)
,A.Name
,B.Order
,C.AmountValue
FROM Table1 A
LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
LEFT JOIN AmountQuery C
ON a.ID = c.ID
AND c.RN = 1
here is SQLFiddle to show how it works.
http://sqlfiddle.com/#!4/696b6/36
Probably, LIMIT will do the job for you selecting just one record from the subquery (It worked for me in MySQL. I do not have Oracle, but I think it may be similar). Try something like this:
SELECT TO_CHAR(ROWNUM),
A.Name,
B.Order,
COALESCE( C.AMOUNT ) as AMOUNT,
FROM Table1 A LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
LEFT JOIN ( SELECT ROUND(LAST_ORDER_AMOUNT,5) AS AMOUNT FROM ORDERS WHERE REQUEST_LEVEL='N' ORDER BY O_DATE DESC ) C ON C.ID = A.id
group by A.id;

How to compare two rows in SQL Server

I'm used to mysql when you can do that with no problems. I would like to run the following statement in SQL Server however it doesn't see the column C_COUNT.
SELECT
A.customers AS CUSTOMERS,
(SELECT COUNT(ID) FROM Partners_customers B WHERE A.ID = B.PIID) AS C_COUNT
FROM Partners A
WHERE CUSTOMERS <> [C_COUNT]
Is it possible to utilize any mathematical operations in the SELECT area like
SELECT (CUSTOMERS - C_COUNT) AS DIFFERENCE
SQL Server does not allow you to use aliases in the WHERE clause. You'll have to have something like this:
SELECT *, Customers - C_COUNT "Difference"
FROM (
SELECT
A.customers AS CUSTOMERS,
(SELECT COUNT(ID)
FROM Partners_customers B WHERE A.ID = B.PIID)
AS C_COUNT FROM Partners A
) t
WHERE CUSTOMERS <> [C_COUNT]
Or, better yet, eliminating an inline count:
select A.customers, count(b.id)
FROM Partners A
LEFT JOIN Partners_customers B ON A.ID = B.PIID
Group By A.ID
having a.customers <> count(b.id)
WITH A AS
(
SELECT
A.customers AS CUSTOMERS,
(SELECT COUNT(ID) FROM Partners_customers B WHERE A.ID = B.PIID) AS C_COUNT
FROM Partners A
WHERE CUSTOMERS <> [C_COUNT]
)
SELECT
*,
(CUSTOMERS - C_COUNT) AS DIFFERENCE
FROM A
Completely untested....
(select * from TabA
minus
select * from TabB) -- Rows in TabA not in TabB
union all
(
select * from TabB
minus
select * from TabA
) -- rows in TabB not in TabA

SQL: Turn a subquery into a join: How to refer to outside table in nested join where clause?

I am trying to change my sub-query in to a join where it selects only one record in the sub-query. It seems to run the sub-query for each found record, taking over a minute to execute:
select afield1, afield2, (
select top 1 b.field1
from anothertable as b
where b.aForeignKey = a.id
order by field1
) as bfield1
from sometable as a
If I try to only select related records, it doesn't know how to bind a.id in the nested select.
select afield1, afield2, bfield1
from sometable a left join (
select top 1 id, bfield, aForeignKey
from anothertable
where anothertable.aForeignKey = a.id
order by bfield) b on
b.aForeignKey = a.id
-- Results in the multi-part identifier "a.id" could not be bound
If I hard code values in the nested where clause, the select duration drops from 60 seconds to under five. Anyone have any suggestions on how to join the two tables while not processing every record in the inner table?
EDIT:
I ended up adding
left outer join (
select *, row_number() over (partition by / order by) as rank) b on
b.aforeignkey = a.id and b.rank = 1
went from ~50 seconds to 8 for 22M rows.
Try this:
WITH qry AS
(
SELECT afield1,
afield2,
b.field1 AS bfield1,
ROW_NUMBER() OVER(PARTITION BY a.id ORDER BY field1) rn
FROM sometable a LEFT JOIN anothertable b
ON b.aForeignKey = a.id
)
SELECT *
FROM qry
WHERE rn = 1
Try this
select afield1,
afield2,
bfield1
from sometable a
left join
(select top 1 id, bfield, aForeignKey from anothertable where aForeignKey in(a.id) order by bfield) b on b.aForeignKey = a.id