converting a sub query into self join - sql

I have this query in which i want to find who are all the other authors are for each title in which the author is Mr.X
The query I wrote for that is:
SELECT DISTINCT (author_name) as AUTHORS
from table1
where title = (Select title from table1 where (author_name) = 'X');
I got the ERROR: more than one row returned by a subquery used as an expression
I think to avoid this error i should use a self join but I'm not able to figure out how to do it.

your subquery returning more than 1 record and in such case you can't use = operator rather You should use IN operator to check against multiple values like below
where title in (Select title from table1 where (author_name) = 'X')
So, your query should look like
SELECT DISTINCT (author_name) as AUTHORS
from table1
where title in (Select title from table1 where (author_name) = 'X');
To change it to join instead
SELECT DISTINCT (t1.author_name) as AUTHORS
from table1 t1
join table1 t2
on t1.title = t2.title

An extra answer, in my opinion the performance of your query improves using: "count"
SELECT DISTINCT (author_name) as AUTHORS
from table1 t1
where ISNULL((Select COUNT(t2.title) from table1 t2 where (author_name) = 'X' AND t1.title = t2.title), 0) > 0

Related

How to use a subquery result for another sql select?

I want to use the result of a sql query and send another query based on the result.
Exmaple (of course real live query is more complex):
table1: name, age
table2: name, age, field1, fieldN
First query:
select name, age from table1 where age > 18.
Now I'd like to find all entries from table2 that match the multiple resulting fields of the first query.
Important note: I want to retrieve the full rows of table2 where the match is.
But how?
If you want to automatically join based on matching column names, then you can use a NATURAL JOIN:
WITH query1 AS (
SELECT age, name FROM table1 WHERE age > 18
)
SELECT age, name, t2.field1, t2.fieldN
FROM table2 t2 NATURAL JOIN query1;
Now, while NATURAL JOIN is generally not recommended, as it is really weak because your queries using it can easily brake due to schema changes, it may be OK for hand ad-hoc queries, or for queries, like the above, where you can make the columns used explicit. In either case, I advise against it and use the common join style:
WITH query1 AS (
SELECT age, name FROM table1 WHERE age > 18
)
SELECT t2.age, t2.name, t2.field1, t2.fieldN
FROM table2 t2 JOIN query1 q1 ON t2.age = q1.age AND t2.name = t1.name;
Now I'd like to:
find
all entries from table2
that match the multiple resulting fields
of the first query
SELECT * -- find
FROM table2 t2 -- from t2
WHERE EXISTS (
SELECT * FROM table1 t1
WHERE t1.name = t2.name -- that match
AND t1.age = t2.age -- Huh? "multiple matching fields" ?
AND t1.age > 18 -- with the same condition
);
Actually this is what I was looking for, but thanks for any help:
select * from table2 where (name, age) IN (
select name, age from table1 where age > 18
)
Query build based on MS sql server
select t1.*
from table1 as t1
join table2 as t2 on t1.name=t2.name and t1.age=t2.age
where t2.age > 18

Select from another table if record not found in the first table - SQL Server 2012

Here is the situation. I have two parameters to query:
Item_code
Item_type
The first_table contains:
Item_Code,Item_Characteristics
The second_table contains:
Item_Type,Item_Characteristics
My goal is to get the item_characteristics. If the specific item is not found in the first table, I would want to use the Item_type to get them from the second table.
Any way this can be done in a single query?
I am using SQL Server 2012.
One way of doing this uses not exists:
select t1.Item_Characteristics
from t1
where t1.item_code = #Item_Code
union all
select t2.Item_Characteristics
from t2
where t2.item_type = #Item_Type and
not exists (select 1 from t1 where t1.item_code = #Item_Code);
You can try with a FULL JOIN in case Item_Code and Item_Type are of the same type:
SELECT COALESCE(t1.Item_Characteristics, t2.Item_Characteristics) AS Item_Characteristics
FROM table1 AS t1
FULL JOIN table2 AS t2
ON t1.Item_Code = t2.Item_Type
WHERE COALESCE(t1.Item_Code, t2. Item_Type) = #param
Let me know if this works -
select isnull(a.Item_Characteristics,b.item_type)
from first_table as a
left join second_table as b
on a.Item_Characteristics = b.Item_Characteristics
where a.Item_code = #itemcode and b.Item_type = #itemtype

How to simplify this query with sql joins?

my_table has 4 columns: id integer, value integer, value2 integer, name character varying
I want all the records that:
have the same value2 as a record which name is 'a_name'
have a field value inferior to the one of a record which name is 'a_name'
And I have satisfying results with the following query:
select t.id
from my_table as t
where t.value < ( select value from my_table where name = 'a_name')
and s.value2 = (select value2 from my_table where name = 'a_name');
But is it possible to simplify this query with sql joins ?
Joining on the same table is still too much intricate in my mind. And I try to understand with this example.
What I happened so far trying, is a result full of dupplicates:
select t2.id
from my_table as t
inner join my_table as t2 on t2.value2 = t.value2
where t2.value < ( select value from my_table where name = 'a_name');
I think this will solve your problem.
select t1.id
from my_table as t1
join my_table as t2
on t1.value2 = t2.value2
and t2.name = 'a_name'
and t1.value < t2.value
You should use self join instead of inner join see this
http://msdn.microsoft.com/en-us/library/ms177490%28v=sql.105%29.aspx
You can always get distinct results by calling "SELECT distinct t2.id ..."
However, that will not enhance your understanding of inner joins. If you are willing, keep reading on. Let's start by getting all records with name = 'a_name'.
SELECT a.*
FROM my_table as a
WHERE a.name = 'a.name';
A simpler way to perform your inner joins is to understand that the result for the above query is yet another table, formally known as a relation. You can think of it as joining on the same table, but an easier way to think of it is as "joining on the result of this query". Lets put this to the test.
SELECT other.id
FROM my_table as a,
INNER JOIN my_table as other ON other.value2 = a.value2
WHERE a.name = 'a_name'
AND other.value < a.value;
If the first query (all rows with name = 'a_name') has many results, you stand a good chance of the second query having duplicates, because the inner join between aliases 'a' and 'other' is a subset of their cross product.
Edits: Grammar, Clarity
please try this
select t.id
from my_table as t
inner join
(select value from my_table where name = 'a_name')t1 on t.value<t1.value
inner join
(select value2 from my_table where name = 'a_name')t2 on t.value2=t2.value2

Is it possible to use subquery in join condition in Access?

In postgresql I can use subquery in join condition
SELECT *
FROM table1 LEFT JOIN table2
ON table1.id1 = (SELECT id2 FROM table2 LIMIT 1);
But when I try to use it in Access
SELECT *
FROM table1 LEFT JOIN table2
ON table1.id1 = (SELECT TOP 1 id2 FROM table2);
I get syntax error. Is it actually impossible in Access or just my mistake?
I know that I can get the same result with WHERE, but my question is about possibilities of JOIN in Access.
It's not possible, per the MSDN documentation:
Syntax
FROM table1 [ LEFT | RIGHT ] JOIN table2 ON table1.field1 compopr table2.field2
And (emphasis mine):
field1, field2: The names of the fields that are joined. The fields must be of the same data type and contain the same kind of data, but they do not need to have the same name.
It appears you can't even have hard-coded values in your join; you must specify the column name to join against.
In your case, you would want:
SELECT *
FROM Table1
LEFT JOIN (
SELECT DISTINCT TOP 1 ID
FROM Table2
ORDER BY ID
) Table2Derived ON Table1.ID = Table2Derived.ID

SQL Server update statement using a join on multiple columns

Having some trouble here.
Table 1:
CID, Name, HID
(001-233, Test1, 12345)
Table 2:
CID, Name, HID, Primary
(001-233, Test1, 12345, '')
Want to update Table2 where a join exists with Table1 with a constant value called 'Y'
So statement is as follows:
UPDATE T2 SET T2.Primary = 'Y'
FROM T2
INNER JOIN T1
ON (T1.CID = T2.CID
AND T1.HID = T2.HID)
This statement just ends up updating all the rows, it's like it only does a join on one id and not the other? I finally gave up and did a WHERE IN subquery with a single "id" by concatenating the two ide fields CID+HID. But I want to understand why this didnt work using the proper join.
Table1 is a CTE..
update t2
set (t2.primary) = (select 'Y' from t1 where T1.CID = T2.CID AND T1.HID = T2.HID)