Does not Recognize Column in Where Clause when Joining Tables - sql

SELECT * FROM a
JOIN (SELECT * FROM b WHERE b.aId = a.Id) AS c ON c.aId = a.Id
It says does not recognize: a.Id in the Where Clause.
I know its probably cause im using a temp table and a.Id cannot be passed through but is there any way we can do that?
Because here is what actually happens
SELECT *
FROM a
JOIN (SELECT * FROM b
WHERE b.aId = a.Id
ORDER BY b.dateReg DESC
LIMIT 1) AS c ON c.aId = a.Id
I need the ORDER BY b.dateReg DESC LIMIT 1 as it returns me the last row that assosiates with the a Table.. If you require i can post the Create Query

-- find last rows on b
select * from b x
where exists(
select id
from b y
where y.id = b.id
having max(y.dateReg) = x.dateReg
group by id
)
-- then join that b to a, this is the final query:
select * from a
join
(
select * from b x
where exists(
select id
from b y
where y.id = b.id
having max(y.dateReg) = x.dateReg
group by id
)
) as last_rows on last_rows.id = a.id
-- simpler:
select *
from a join b x on a.id = x.id
where exists(
select id
from b y
where y.id = b.id
having max(y.dateReg) = x.dateReg
group by id)
-- or if you will use postgres:
select DISTINCT ON (a.id) *
from a join b x on a.id = x.id
order by a.id, b.dateReg DESC
-- look ma! no group by!
-- nothing beats postgresql's simplicity :-)

Try:
SELECT DISTINCT *
FROM A
JOIN B b ON b.aid = a.id
JOIN (SELECT b.aid,
MAX(b.datereg) 'max_datereg'
FROM B b
GROUP BY b.aid) md ON md.aid = b.aid
AND md.max_datereg = b.datereg
If you do want the first record associated with the associate, use:
SELECT DISTINCT *
FROM A
JOIN B b ON b.aid = a.id
JOIN (SELECT b.aid,
MIN(b.datereg) 'min_datereg'
FROM B b
GROUP BY b.aid) md ON md.aid = b.aid
AND md.min_datereg = b.datereg

Related

Looking through 3 tables

I am working on a personal project.
I have the following data
tbl A
id, blah, blah
tbl B
id, id_2
tbl C
id_2, Result
I have check for the following, if id in tbl A exists in tbl B AND if Pass = 'A'.
I can write a query to check for the keys in A exists in B.
Something like,
SELECT * FROM tblA as a
WHERE NOT EXISTS (
SELECT * FROM tblB as b
WHERE a.id = b.id)
And this works fine.
I can also write something with an INNER JOIN
SELECT *
FROM tabC
INNER JOIN tblB ON tblC.id2 = tblB.id2
INNER JOIN tblA ON tblB.id = tblA.id
WHERE Result = 'A' GROUP BY id
But I can't seem to figure out how to combine both these queries together.
you can try like below
SELECT c.*
FROM tabC c
INNER JOIN tblB b ON c.id2 = b.id2
INNER JOIN tblA a ON b.id = a.id
WHERE Result = 'A'
and NOT EXISTS (
SELECT 1 FROM tblB as b1
WHERE a.id = b1.id)

SQL query inner join and where on the second table

I have a oracle database and I'm trying to query data in table1 and inner join with another table2 where one of the columns(date) is equal to the most recent date and another column in table2(built) is equal to 'yes'. This query below is not picking up the where function and can't pinpoint why
SELECT id, b, c, d
FROM table1 a
INNER JOIN table2 b on b.id = a.id
WHERE b.date =(SELECT MAX(date) FROM table2) AND b.built = 'yes'
Actual query
SELECT m_tp_str, m_tp_trn, m_tp_dte, m_tp_buy, m_tp_qtyeq, m_tp_nom, m_instr,
m_tp_p, m_tp_status2
FROM HA_PRD_DM.TP_ALL_REP a INNER JOIN HA_PRD_DM.UDF_CURR_REP b
ON a.m_udf_ref2 = b.m_nb
WHERE b.m_rep_date2 = (SELECT MAX(c.m_rep_date2) FROM HA_PRD_DM.UDF_CURR_REP c)
AND b.m_purpose = 'yes'
You can do this using analytic functions:
SELECT id, b, c, d
FROM table1 a INNER JOIN
(SELECT b.*, MAX(date) OVER (PARTITION BY b.id) as max_date
FROM table2 b
WHERE built = 'yes'
) b
ON b.id = a.id AND b.max_date = b.date;

sql - multiple layers of correlated subqueries

I have table A, B and C
I want to return all entries in table A that do not exist in table B and of that list do not exist in table C.
select * from table_A as a
where not exists (select 1 from table_B as b
where a.id = b.id)
this gives me the first result of entries in A that are not in B. But now I want only those entries of this result that are also not in C.
I tried flavours of:
select * from table_A as a
where not exists (select 1 from table_B as b
where a.id = b.id)
AND
where not exists (select 1 from table_C as c
where a.id = c.id)
But that isnt the correct logic. If there is a way to store the results from the first query and then select * from that result that are not existent in table C. But I'm not sure how to do that. I appreciate the help.
Try this:
select * from (
select a.*, b.id as b_id, c.id as c_id
from table_A as a
left outer join table_B as b on a.id = b.id
left outer join table_C as c on c.id = a.id
) T
where b_id is null
and c_id is null
Another implementation is this:
select a1.*
from table_A as a1
inner join (
select a.id from table_A
except
select b.id from table_B
except
select c.id from table_c
) as a2 on a1.id = a2.id
Note the restrictions on the form of the sub-query as described here. The second implementation, by most succinctly and clearly describing the desired operation to SQL Server, is likely to be the most efficient.
You have two WHERE clauses in (the external part of) your second query. That is not valid SQL. If you remove it, it should work as expected:
select * from table_A as a
where not exists (select 1 from table_B as b
where a.id = b.id)
AND
not exists (select 1 from table_C as c -- WHERE removed
where a.id = c.id) ;
Tested in SQL-Fiddle (thnx #Alexander)
how about using LEFT JOIN
SELECT a.*
FROM TableA a
LEFT JOIN TableB b
ON a.ID = b.ID
LEFT JOIN TableC c
ON a.ID = c.ID
WHERE b.ID IS NULL AND
c.ID IS NULL
SQLFiddle Demo
One more option with NOT EXISTS operator
SELECT *
FROM dbo.test71 a
WHERE NOT EXISTS(
SELECT 1
FROM (SELECT b.ID
FROM dbo.test72 b
UNION ALL
SELECT c.ID
FROM dbo.test73 c) x
WHERE a.ID = x.ID
)
Demo on SQLFiddle
Option from #ypercube.Thank for the present;)
SELECT *
FROM dbo.test71 a
WHERE NOT EXISTS(
SELECT 1
FROM dbo.test72 b
WHERE a.ID = b.ID
UNION ALL
SELECT 1
FROM dbo.test73 c
WHERE a.ID = c.ID
);
Demo on SQLFiddle
I do not like "not exists" but if for some reason it seems to be more logical to you; then you can use a alias for your first query. Subsequently, you can re apply another "not exists" clause. Something like:
SELECT * FROM
( select * from tableA as a
where not exists (select 1 from tableB as b
where a.id = b.id) )
AS A_NOT_IN_B
WHERE NOT EXISTS (
SELECT 1 FROM tableC as c
WHERE c.id = A_NOT_IN_B.id
)

Getting MIN date

I have a table(A) that looks something like:
ID Date
1 2012/01/12
2 2012/01/01
3 2012/01/03
4 2012/03/12
If I wanted to grab the MIN date for this query, would I just group by?
select
a.ID,
MIN(a.DATE),
b.name,
c.price
FROM
tablea a inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
You want a window function. The correct expression is:
select a.id,
min(a.date) over () as mindate,
b.name, c.price
. . .
This says to get the min of the date over the data. There is no partition, so it gets it over all the data.
If you are looking for those that had the minimum date, then you can do this:
select
a.ID,
a.DATE,
b.name,
c.price
FROM tablea a
INNER JOIN
(
SELECT Id, MIN(Date) AS MinDate
FROM tablea
GROUP BY Id
) As minA ON a.date = mina.mindate AND a.id = mina.id
inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
WITH recordList
as
(
select a.ID,
a.DATE,
b.name,
c.price,
DENSE_RANK() OVER (PARTITION BY a.ID
ORDER BY a.Date ASC) rn
FROM tablea a
inner join tableb b on a.ID = b.ID
inner join tablec c b.ID = c.ID
)
SELECT ID, DATE, name, Price
FROM recordList
WHERE rn = 1

my query is giving me the wrong ID

I've got four tables: A, B, C, D. D has a FK to C, C has a FK to B, B has a FK to A. Each table has an ID column. In addition to ID and CID, table D has Value and Timestamp (an integer). Given a certain time, I need the row from D before the Timestamp but closest to it for each CID -- Unless there are no rows before the Timestamp, in which case I need the first value after after the Timestamp. I'm using Sqlite.
Leaving out this last requirement, I attempted to get the values before the Timestamp with this query, but the ID returned is wrong:
SELECT *
FROM D d
INNER JOIN C c ON d.CID = c.ID
INNER JOIN B b ON C.BID = b.ID
WHERE b.AID = #AID AND d.Timestamp =
(
SELECT MAX(d2.Timestamp)
FROM D d2
WHERE d2.Timestamp < #StartTime
AND d2.CID = D.CID
)
This query should get the last entry before #StartTime in the first part of the query (before the UNION ALL) then combine it with the first entry after #StartTime. All that remains is to pick the smallest entry for each CID.
SELECT d2.*
FROM (
SELECT D.ID, MAX(D.Timestamp)
FROM D d
INNER JOIN C c ON c.ID = d.CID
INNER JOIN B b on b.ID = c.BID
WHERE b.AID = #AID AND d.Timestamp <= #StartTime
GROUP BY d.CID) AS results
INNER JOIN D d2 ON d2.ID = results.ID
UNION ALL
SELECT d2.*
FROM (
SELECT D.ID, MIN(D.Timestamp)
FROM D d
INNER JOIN C c ON c.ID = d.CID
INNER JOIN B b on b.ID = c.BID
WHERE b.AID = #AID AND d.Timestamp > #StartTime
GROUP BY d.CID) AS results
INNER JOIN D d2 ON d2.ID = results.ID
This might work, but still a little confused over exactly what you want.
SELECT *,
(CASE WHEN d.Timestamp < #StartTime THEN 1 ELSE 0) AS timeCheck
FROM D d
INNER JOIN C c ON d.CID = c.ID
INNER JOIN B b ON C.BID = b.ID
WHERE b.AID = #AID
ORDER BY timeCheck DESC, d.Timestamp DESC
LIMIT 0,1
Updated