multiple subquery error "invalid identifier" - sql

Im working on this code but i keep getting invalid identifer for t2.nabp_num
`with t1 as (query1),
t2 as (query2)
Select t1.*, t2.device_count,
d.* from t1
inner join t2 on
t1.nabp_num = t2.nabp_num and
t1.dt = t2.dt and
t1.d_member = t2.d_member
inner join drug_product d on
t1.d_product_id = d.product_id
order by claim_count desc;`
i get invalid identifier

As already commented, you can't reference something that doesn't exist.
It would certainly help if you posted actual query instead of invalid
with t1 as (query1 --> what is "query1"?
Order by ...
Anyway: as NABP_NUM is referenced here:
inner join t2 on t1.nabp_num = t2.nabp_num
it means that it has to be part of both t1 and t2. However, as t2 CTEs result is derived from t1, maybe you don't need t1 at all ...
If you add all columns that are currently missing in either select column list or group by clause, query would look like this (see comments within code):
WITH
t1
AS
(SELECT d_member_id,
dt,
device_type,
claim_id,
nabp_num, --> add NABP_NUM
d_member_hq_id --> add D_MEMBER_HQ_ID
d_drug_product_id --> add D_DRUG_PRODUCT_ID
FROM some_table --> which table?
), --> remove ORDER BY, it is useless here
t2
AS
( SELECT d_member_id,
dt,
nabp_num, --> add NABP_NUM
d_member_hq_id, --> add D_MEMBER_HQ_ID
COUNT (DISTINCT device_type) AS device_count,
COUNT (DISTINCT claim_ID) AS claim_count
FROM t1
GROUP BY d_member_id, dt, nabp_num, d_member_hq_id) --> add NABP_NUM and D_MEMBER_HQ_ID
SELECT t1.*, t2.device_count, d.*
FROM t1
INNER JOIN t2
ON t1.nabp_num = t2.nabp_num
AND t1.dt = t2.dt
AND t1.d_member_hq_id = t2.d_member_hq_id
INNER JOIN vmd_drug_product d
ON t1.d_drug_product_id = d.d_drug_product_id
ORDER BY t2.claim_count DESC;
Even though this shouldn't return any syntax errors any more (presuming columns used here really exist in some_table), I can't tell whether this will - or will not - return desired result.

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;

missing FROM-clause entry for table when using string_agg

I have this query to try to search for the course that fulfills 3 requirements.
select
course.id,
course.title,
course.number,
string_agg(requirement.description,'; ' order by requirement.description)
from course
join
(
select course.id, course.title, course.number
from requirement join course_requirement
on (requirement.id=course_requirement.requirement)
join course on (course.id=course_requirement.course)
where requirement.description='Human Behavior'
) as c1
on (c1.id=course.id)
join
(
select course.id, course.title, course.number
from requirement
join course_requirement
on (requirement.id=course_requirement.requirement)
join course
on (course.id=course_requirement.course)
where requirement.description='Intercultural'
) as c2
on (c1.id=c2.id)
join
(
select course.id, course.title, course.number
from requirement
join course_requirement
on (requirement.id=course_requirement.requirement)
join course
on (course.id=course_requirement.course)
where requirement.description='Religion'
) as c3
on (c1.id=c3.id)
group by course.id, course.title, course.number;
However, I receive this message: ERROR: missing FROM-clause entry for table "requirement"
LINE 1: ...course.id, course.title, course.number,string_agg(requiremen...
Can you tell me where did I get the query wrong?
Thank you so much!
I don't see the point of the three joined subqueries, which differ only in the requirement description in the WHERE clause. Instead, you might try a single query which uses WHERE IN to capture the three descriptions you want in your result set. This also fixes the problem you had with string_agg(), where you were trying to aggregate something from a subquery not reachable in the outer query.
Try the following query:
select
t1.id,
t1.title,
t1.number,
string_agg(t3.description, '; ' order by t3.description)
from course t1
inner join course_requirement t2
on t1.id = t2.course
inner join requirement t3
on t2.requirement = t3.id
where t3.description in ('Human Behavior', 'Intercultural', 'Religion')
group by t1.id, t1.title, t1.number;

Left Join with duplicate keys in the right table

I'm trying merging 2 tables as follow
SELECT * FROM T1
LEFT JOIN T2 ON T1.EMPnum = T2.EMPnum
The above works well but I need the joining to use only the first appearance of the common key EMPnum record in table T2 so that the query returns exactly the same number of rows as T1
Thanks Avi
SQL tables are inherently unordered, so there is no such thing as a "first" key. In most databases, you can do something like this:
with t2 as (
select t2.*, row_number() over (partition by EMPnum order by id) as seqnum
from t2
)
select *
from t1 left join
t2
on t1.EMPnum = t2.EMPnum and t2.seqnum = 1;
Here id is just any column that specifies the ordering. If none exist, you can use EMPnum to get an arbitrary row.

SQL - remove duplicates from left join

I'm creating a joined view of two tables, but am getting unwanted duplicates from table2.
For example: table1 has 9000 records and I need the resulting view to contain exactly the same; table2 may have multiple records with the same FKID but I only want to return one record (random chosen is ok with my customer). I have the following code that works correctly, but performance is slower than desired (over 14 seconds).
SELECT
OBJECTID
, PKID
,(SELECT TOP (1) SUBDIVISIO
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS ProjectName
,(SELECT TOP (1) ASBUILT1
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS Asbuilt
FROM dbo.table1 AS t1
Is there a way to do something similar with joins to speed up performance?
I'm using SQL Server 2008 R2.
I got close with the following code (~.5 seconds), but 'Distinct' only filters out records when all columns are duplicate (rather than just the FKID).
SELECT
t1.OBJECTID
,t1.PKID
,t2.ProjectName
,t2.Asbuilt
FROM dbo.table1 AS t1
LEFT JOIN (SELECT
DISTINCT FKID
,ProjectName
,Asbuilt
FROM dbo.table2) t2
ON t1.PKID = t2.FKID
table examples
table1 table2
OID, PKID FKID, ProjectName, Asbuilt
1, id1 id1, P1, AB1
2, id2 id1, P5, AB5
3, id4 id2, P10, AB2
5, id5 id5, P4, AB4
In the above example returned records should be id5/P4/AB4, id2/P10/AB2, and (id1/P1/AB1 OR id1/P5/AB5)
My search came up with similar questions, but none that resolved my problem. link, link
Thanks in advance for your help. This is my first post so let me know if I've broken any rules.
This will give the results you requested and should have the best performance.
SELECT
OBJECTID
, PKID
, t2.SUBDIVISIO,
, t2.ASBUILT1
FROM dbo.table1 AS t1
OUTER APPLY (
SELECT TOP 1 *
FROM dbo.table2 AS t2
WHERE t1.PKID = t2.FKID
) AS t2
Your original query is producing arbitrary values for the two columns (the use of top with no order by). You can get the same effect with this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, min(ProjectName) as ProjectName, MIN(asBuilt) as AsBuilt
FROM dbo.table2
group by fkid
) t2
ON t1.PKID = t2.FKID
This version replaces the distinct with a group by.
To get a truly random row in SQL Server (which your syntax suggests you are using), try this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, ProjectName, AsBuilt,
ROW_NUMBER() over (PARTITION by fkid order by newid()) as seqnum
FROM dbo.table2
) t2
ON t1.PKID = t2.FKID and t2.seqnum = 1
This assumes version 2005 or greater.
If you want described result, you need to use INNER JOIN and following query will satisfy your need:
SELECT
t1.OID,
t1.PKID,
MAX(t2.ProjectName) AS ProjectName,
MAX(t2.Asbuilt) AS Asbuilt
FROM table1 t1
JOIN table2 t2 ON t1.PKID = t2.FKID
GROUP BY
t1.OID,
t1.PKID
If you want to see all rows from left table (table1) whether it has pair in right table or not, then use LEFT JOIN and same query will gave you desired result.
EDITED
This construction has good performance, and you dont need to use subqueries.