The multi-part identifier could not be bound - SQL Server 2014 - sql

I am trying to solve the error in the below query
Yes I have checked many same questions but still can not figure out the solution
The error:
The multi-part identifier "Table_2.id" could not be bound.
When I remove the inner join the query runs perfectly fine
I have to solve this problem without turning it into explicit joins because i have so many dynamic filtering which add and x=y clauses to the end of the query
Thank you
SELECT TOP 10 username,
NAME,
table_1.authoritylevel,
totalcount,
avglevel,
table_2.pokemonid,
pokemonlevel,
table_2.id,
pokemonexp,
battlecount,
battlevictorycount,
table_1.userid
FROM table_1,
table_2,
table_3,
table_4
LEFT OUTER JOIN (SELECT Count(table_5.offereruserid) AS OfferCount,
table_5.offereduserspokemonsid
FROM table_5
GROUP BY offereduserspokemonsid) innerQuestion
ON innerQuestion.offereduserspokemonsid = table_2.id
WHERE table_3.pokemonid = table_2.pokemonid
AND pokemonplace = 'trade'
AND table_4.pokemonid = table_2.pokemonid
AND table_2.userid = table_1.userid
AND table_2.userid != 1

If you are keen on keeping the implicit joins, you could split your query into several result sets using WITH. According to this article, you can no longer do "implicit outer joins." Give this a try:
WITH OfferCounts as
(
SELECT Count(table_5.offereruserid) AS OfferCount, table_5.offereduserspokemonsid
FROM table_5
GROUP BY offereduserspokemonsid
),
EverythingElse AS
(
SELECT TOP 10 username,
NAME,
table_1.authoritylevel,
totalcount,
avglevel,
table_2.pokemonid,
pokemonlevel,
table_2.id,
pokemonexp,
battlecount,
battlevictorycount,
table_1.userid
FROM table_1,
table_2,
table_3,
table_4,
WHERE table_3.pokemonid = table_2.pokemonid
AND pokemonplace = 'trade'
AND table_4.pokemonid = table_2.pokemonid
AND table_2.userid = table_1.userid
AND table_2.userid != 1
)
Select *
From EverythingElse t1
left join OfferCounts t2 on t1.offereduserspokemonsid = t2.id

The specific problem comes from the use of implicit joins first and then an explicit join. Lesser lines of code is not a very good reason to use implicit joins, specially since it's deprecated.
Another considerations would be to use table aliases, and also to prefix every column with the corresponding table alias, even if the column is unique between those tables for readability and a code that's easier to maintain.
You are also missing the GROUP BY needed for your aggregation function. All in all, the fixed code would be:
SELECT TOP 10 username,
NAME,
T1.authoritylevel,
totalcount,
avglevel,
T2.id,
T2.pokemonid,
pokemonlevel,
pokemonexp,
battlecount,
battlevictorycount,
T1.userid,
Count(T5.offereruserid) AS OfferCount
FROM Table_1 T1
INNER JOIN Table_2 T2
ON T1.userid = T2.userid
INNER JOIN Table_3 T3
ON T2.pokemonid = T3.pokemonid
INNER JOIN Table_4 T4
ON T2.pokemonid = T4.pokemonid
INNER JOIN Table_5 T5
ON T5.offereduserspokemonsid = T2.id
WHERE pokemonplace = 'trade'
AND T2.userid != 1
GROUP BY username,
NAME,
T1.authoritylevel,
totalcount,
avglevel,
T2.id,
T2.pokemonid,
pokemonlevel,
pokemonexp,
battlecount,
battlevictorycount,
T1.userid;
But, as I said, I suggest that you add the corresponding prefixes to those columns.

Related

Editing result of joined/concatenated table result in PSQL

i have a sql query i'm running that joins & concatenates multiple tables, resulting in new columns, etc. I want to easily edit these fresh column values by double-clicking into the empty portions, like usual, but i read when joining tables they become read-only. I also wanted to attempt a regular INSERT cmd but don't understand what the table name is, since its all resulted from a lengthy query. How can i edit this queried table?
Below, i have pasted the query. For example, this spits out a new column change_products, and i want to edit those values but as mentioned above, cannot after joining/concatenating. Thanks!
SELECT change_ticket,
change_product,
change_desc,
change_state,
security_bulletin,
change_assigned_to,
affected,
remediated
FROM change_tickets t1
LEFT JOIN change_product_link t2 ON t1.id = t2.chg_id
LEFT JOIN (SELECT id, concat(product_name, ' ', product_version) AS change_product FROM products) chg_product ON t2.product_id = chg_product.id
LEFT JOIN change_sb_link t4 ON t1.id = t4.chg_id
LEFT JOIN security_bulletins t5 ON t5.id = t4.sb_id
LEFT JOIN product_sb_link t6 ON t5.id = t6.sb_id
LEFT JOIN (SELECT id, concat(product_name, ' ', product_version) AS affected FROM products) aff_soft ON t6.affected_software_id = aff_soft.id
LEFT JOIN (SELECT id, concat(product_name, ' ', product_version) AS remediated FROM products) rem_soft ON t6.remediated_software_id = rem_soft.id
WHERE change_state NOT IN ('Cancelled', 'Closed - Successful', 'Post-Verify') OR change_state IS NULL
ORDER BY 1

Return only duplicate values in Access SQL

I am having trouble trying to return only duplicate values in a query on Microsoft Access.
Here is my initial query:
SELECT tbl_dbextract_GP.GPNo,
[tbl_dbextract_GP].[GPFirst]+" "+[tbl_dbextract_GP].[GPLast] AS GPName,
Sum(tbl_main_ListLog.count_ToImport) AS ImportCount,
tbl_main_ListLog.SearchSequence
FROM ((tbl_main_ListLog
INNER JOIN tbl_dbextract_GPPractice
ON tbl_main_ListLog.GPPracticeID = tbl_dbextract_GPPractice.Id)
INNER JOIN tbl_dbextract_GP
ON tbl_dbextract_GPPractice.GPId = tbl_dbextract_GP.Id)
WHERE tbl_dbextract_GP.GPNo <> 'G0000'
GROUP BY tbl_dbextract_GP.GPNo,
[tbl_dbextract_GP].[GPFirst]+" "+[tbl_dbextract_GP].[GPLast],
tbl_main_ListLog.SearchSequence;
I only want to return results where there is at least 2 entries per GPNo.
The search sequence is incremental, so basically I am trying to find entries where there has been at least 2 searches.
This was my attempt:
SELECT
tbl_dbextract_GP.GPNo,
[tbl_dbextract_GP].[GPFirst] + " " + [tbl_dbextract_GP].[GPLast] AS GPName,
Sum(tbl_main_ListLog.count_ToImport) AS ImportCount,
tbl_main_ListLog.SearchSequence
FROM (((tbl_main_ListLog
INNER JOIN tbl_dbextract_GPPractice
ON tbl_main_ListLog.GPPracticeID = tbl_dbextract_GPPractice.Id)
INNER JOIN tbl_dbextract_GP
ON tbl_dbextract_GPPractice.GPId = tbl_dbextract_GP.Id)
LEFT JOIN (
SELECT tbl_main_ListLog.GPPracticeID as GPPID,
SUM(tbl_main_ListLog.SearchSequence) as SumSS
FROM tbl_main_ListLog
WHERE SumSS > 1
GROUP BY tbl_main_ListLog.GPPracticeID) SubQ
ON tbl_main_ListLog.GPPracticeID = SubQ.GPPID)
WHERE tbl_dbextract_GP.GPNo <> 'G0000'
GROUP BY tbl_dbextract_GP.GPNo,
[tbl_dbextract_GP].[GPFirst]+" "+[tbl_dbextract_GP].[GPLast],
tbl_main_ListLog.SearchSequence;
This didn't work, as it prompted me to manually enter the value for SumSS on execute, and that didn't return the right results anyway.
This is a sample output (Names redacted) - I want to return results where there is at least 2 entries per GPNo
EDIT: Modified attempt using Tim's solution - returning "Syntax error in JOIN operation":
SELECT
t3.GPNo,
t3.GPFirst + " " + t3.GPLast AS GPName,
SUM(t1.count_ToImport) AS ImportCount,
t1.SearchSequence
FROM (((tbl_main_ListLog t1
INNER JOIN tbl_dbextract_GPPractice t2
ON t1.GPPracticeID = t2.Id)
INNER JOIN tbl_dbextract_GP t3
ON t2.GPId = t3.Id)
INNER JOIN
(
SELECT t3.GPNo
FROM ((tbl_main_ListLog t1
INNER JOIN tbl_dbextract_GPPractice t2
ON t1.GPPracticeID = t2.Id)
INNER JOIN tbl_dbextract_GP t3
ON t2.GPId = g3.Id)
GROUP BY t3.GPNo
HAVING COUNT(*) > 1
) t4
ON t3.GPNo = t4.GPNo)
WHERE
t3.GPNo <> 'G0000'
GROUP BY
t3.GPNo,
t3.GPFirst + " " + t3.GPLast,
t1.SearchSequence;
Given that this is MS Access, which does not support analytic functions, doing a join to another subquery to impose the restriction on the number of searches seems like a reasonable approach, and your second attempt does not look far off. But you should be using the HAVING operator instead of WHERE, with a few other changes:
SELECT
t3.GPNo,
t3.GPFirst + " " + t3.GPLast AS GPName,
SUM(t1.count_ToImport) AS ImportCount,
t1.SearchSequence
FROM tbl_main_ListLog t1
INNER JOIN tbl_dbextract_GPPractice t2
ON t1.GPPracticeID = t2.Id
INNER JOIN tbl_dbextract_GP t3
ON t2.GPId = t3.Id
INNER JOIN
(
SELECT t3.GPNo
FROM tbl_main_ListLog t1
INNER JOIN tbl_dbextract_GPPractice t2
ON t1.GPPracticeID = t2.Id
INNER JOIN tbl_dbextract_GP t3
ON t2.GPId = t3.Id
GROUP BY t3.GPNo
HAVING COUNT(*) > 1
) t4
ON t3.GPNo = t4.GPNo
WHERE
t3.GPNo <> 'G0000'
GROUP BY
t3.GPNo,
t3.GPFirst + " " + t3.GPLast,
t1.SearchSequence;
In the subquery which I have aliased as t4, I do the same set of joins as your original query, but I then aggregate only by the GPNo. Also, I added a HAVING clause requiring that a GPNo appear two or more times in order to be retained in the result set. This subquery then filters off non matching GPNo records in your original query.
Add the Count(1) As Countr to your query and apply condition Countr>1 (apply HAVING clause as explained above).
Alternatively, in order to simplify your task, you can save the original working query as the intermediate one, e.g. Sub_With_Duplicates (Access has that feature), and then build another one (eg. Qry_No_Duplicates on the top of the intermediate and simply apply WHERE Countr>1 clause to that field. This should work.

Oracle join optimization

I have the following SQL query:
select dres.colA,
dres.colP,
dres.ID,
dre.ID,
dre.colED,
dre.VID,
vpp.VID,
vpp.colDESC
from table1 dres
left join table2 dre on dres.ID = dre.ID
left join table3 vpp on vpp.VID = dre.VID
where dre.START_TIME >= date '2017-01-01';
Do you have any suggestion how the query can work better (or should look)?
Something like:
...where dres.ID in (select * from table2
where VID in (select * from table3))....
First, your where clause changes the outer joins to inner joins. So, start by writing the query as:
select dres.colA, dres.colP, dres.ID,
dre.ID, dre.colED, dre.VID,
vpp.VID, vpp.colDESC
from table1 dres join
table2 dre
on dres.ID = dre.ID join
table3 vpp
on vpp.VID = dre.VID
where dre.START_TIME >= date '2017-01-01';
The place to start is with indexes on table2(id, vid, start_time, colED) and table3(vid, colDESC).
It is possible that an alternative indexing strategy would work: table2(start_time, id, vid, colED). This would allow the where clause to use the index. But that particular where clause may not be highly selective.

Query using CASE, WHEN, THEN in postgresql not working

I have three tables, tbl_doctors_details, tbl_time and tbl_token.
I have to select the details from tbl_time or tbl_token. That is if for particular doctor in hospital have t_type is time then select from tbl_time else select from tbl_token.
For example, for doctor_id is 100 and hospital_id 1, the t_type is time. So for this user, details should select from tbl_time table.
Below is the sample structure and data of three tables:
How can I use CASE condition in query here?
I tried:
SELECT *
FROM
( SELECT * CASE WHEN t_type= 'time' FROM dbname.tbl_doctors_details t1 THEN
dbname.tbl_time t2
ELSE
dbname.tbl_token t2
WHERE t1.hospital_id=t2.hospital_id AND t1.doctor_id=t2.doctor_id);
I know the query is not working, but how can I make the query working?
You need to join both tables using two LEFT JOINs and then COALESCE to find the matching data:
SELECT t1.*,
colaesce(t_time.hospid, t_token.hospid),
colaesce(t_time.start, t_token.start)
FROM dbname.tbl_doctors_details t1
LEFT JOIN dbname.tbl_time t_time
ON t1.doctor_id=t_time.doctor_id
AND t1.t_type= 'time'
LEFT JOIN dbname.tbl_token t_token
ON t1.doctor_id=t_token.doctor_id
AND t1.t_type= 'token';
Use CASE WHEN in your SELECT and LEFT JOIN both tables. In both LEFT JOIN use the condition of t_type to join on the tables. In your SELECT you can now check whether table t1 or t2 was joined and select the preferred column. Here's a sample (the selected column is just a sample to illustrate):
SELECT CASE WHEN t1.id IS NULL THEN t2.id ELSE t1.id END AS joined_id
FROM tbl_doctors_details as tbl_base
LEFT JOIN tbl_time t1 ON t1.t_type = 'time' AND t1.doc_id = tbl_base.doc_id
LEFT JOIN tbl_token t2 ON t2.t_type = 'token' AND t2.doc_id = tbl_base.doc_id
Serious smell of doing homework for someone here.. Meh
SELECT
doctors.*
, CASE
WHEN doctors.type = 'time' THEN time.start
ELSE token.start
END AS start
FROM
doctors
LEFT OUTER JOIN time
ON time.doc_id = doctors.doc_id
AND time.hospital_id = doctors.hospital_id
AND doctors.t_type = 'time'
LEFT OUTER JOIN token
ON token.doc_id = doctors.doc_id
AND token.hospital_id = doctors.hospital_id
AND doctors.t_type = 'token'

Getting a ton of duplicates? Left Join incorrect?

Here is a sample of my query:
SELECT ...
TRIM(eml.fxeml1) as "Email Address"
FROM pfship
LEFT JOIN mstfxem fax
ON fax.fxco=pfship.cshco AND fax.fxdiv=pfship.cshdiv AND fax.fxsold=pfship.cshsld
AND fax.fxtype='C' AND TRIM(fax.fxfax1) <> '' AND fax.fxdept LIKE '*F%'
LEFT JOIN mstfxem eml
ON eml.fxco=pfship.cshco AND eml.fxdiv=pfship.cshdiv AND eml.fxsold=pfship.cshsld
AND eml.fxtype='C' AND TRIM(eml.fxeml1) <> '' AND eml.fxdept LIKE '*E%'
WHERE ((pfship.cshco || '/' || pfship.cshdiv) = ?)
AND (? = '*ALL' OR CAST(cshsld AS CHAR(15)) = ?)
AND ...
ORDER BY TRIM(cshnme)
This query should return 9 records. When I remove:
LEFT JOIN mstfxem fax
ON fax.fxco=pfship.cshco AND fax.fxdiv=pfship.cshdiv AND fax.fxsold=pfship.cshsld
AND fax.fxtype='C' AND TRIM(fax.fxfax1) <> '' AND fax.fxdept LIKE '*F%'
LEFT JOIN mstfxem eml
ON eml.fxco=pfship.cshco AND eml.fxdiv=pfship.cshdiv AND eml.fxsold=pfship.cshsld
AND eml.fxtype='C' AND TRIM(eml.fxeml1) <> '' AND eml.fxdept LIKE '*E%'
I get 9 records, but with it I get 360 records. What is wrong with my join?
Thanks
I think the problem is that 1 person can have many emails or faxes, how do I group the results into 1 string per record so I end up with only 9 records?
Nothing is wrong with your join, you have a one to many relationship between the tables.
Depending on what you need there are several techniques. First is the derived table. Write a query to pick out only one record from the one to many table (your requirements should specify which record to pick). Join to that instead. OR you may be able to put further conditions on the left join to get only one record. Some examples of these techniques:
select t1.field1, t2.email
from table1 t1
join (select myid, max(email) as email from table2 group by myid) t2
on t1.myid = t2.myid
Or
select t1.field1, t2.email
from table1 t1
Left join from table2 t2
on t1.myid = t2.myid and t2.active = 1
Or if you want all of the emails in a comma delimited list, that code is database specific and you would need to let us know which database backend you are using.