SQL Server Select Duplicate Column Value - sql

I have the following structure:
TABLE1 TABLE2
id_worker_main id_worker
id_worker_sub name_worker
I need to make a select getting the name_worker for both id_worker_main and id_worker_sub, but I can't. The following query return the same name twice.
SELECT t2.name_worker as main, t2.name_worker as sub
FROM table1
INNER JOIN table2 ON t1.id_worker_main = t2.id_worker AND t1.id_worker_sub = t2.id_worker

You have to join with the same table twice. Just use a different alias for each join
Sql Fiddle Demo
With this workers
INSERT INTO Table2
([id_worker], [name_worker])
VALUES
(1, 'Juan'),
(2, 'Angela'),
(3, 'Peter');
And this relationship
INSERT INTO Table1
([id_worker_main], [id_worker_sub])
VALUES
(1, 2),
(2, 3),
(1, 3);
Use this query
SELECT A.name_worker MAINWORKER, B.name_worker SUBWORKER
FROM Table1 T1
Inner join Table2 A
ON T1.id_worker_main = A.id_worker
Inner join Table2 B
ON T1.id_worker_sub = B.id_worker
OUTPUT
| MAINWORKER | SUBWORKER |
|------------|-----------|
| Juan | Angela |
| Angela | Peter |
| Juan | Peter |

If I understood your problem correctly, you can join table2 multiple times
SELECT t21.name_worker as main, t22.name_worker as sub
FROM table1 t1
JOIN table2 t21 on t21.id_worker = t1.id_worker_main
JOIN table2 t22 on t22.id_worker = t1.id_worker_sub

Related

SQL query returning all rows from Table2

I am trying to join 2 tables and return data if the Table1.codeId is presented on Table2 OR if Table1.codeId = 0. However, It retrieves the data from Table2.
Table1 {
name nvarchar,
codeId int
}
| name | codeId |
|--------|--------|
| Bob | 1 |
| Bob | 2 |
| Chris | 0 |
Table2 {
id int,
codeName nvarchar
}
| id | codeName |
|------|----------|
| 1 | Engineer |
| 2 | Doctor |
| 3 | Dentist |
| 4 | Pilot |
| 5 | Mechanic |
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = t2.id OR t1.codeId = 0)
Expected result:
Bob, 1
John, 2
Chris, 0
You are not required to use Join at all for such condition.
You can use subquery as following, it return same result as your expectation
select name,codeid from table1 where codeid in (select id from table2)
or codeid=0
What if you do it in two separates queries ?
Looking at the outcome, the problem must come from the WHERE clause. The OR seem to always be triggered.
So maybe splitting could do it
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = t2.id)
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = 0)
You can use a left join. Use it to select where there is a code match in Table2 or the code_id is 0.
create table Table1
(
name nvarchar(50),
codeId int
)
create table Table2
(
id int,
codeName nvarchar(50)
)
insert into Table1
VALUES
('Bob', 1),
('John', 2),
('Chris', 0),
('Tom', -1)
-- This should be excluded .. since -1 code doesn't exist in Table2
insert into Table2
VALUES
(1, 'Engineer'),
(2, 'Doctor'),
(3, 'Dentist'),
(4, 'Pilot'),
(5, 'Mechanic')
SELECT t1.name, t1.codeId
FROM dbo.Table1 t1
LEFT JOIN dbo.Table2 t2 ON t1.codeId = t2.id
WHERE t2.id is not NULL or t1.codeId = 0
You have to use left outer join.
please find below query
Select codeid,name
FROM Table1
LEFT OUTER JOIN Table2
ON Table1.codeId=Table2.id;

SQL join that returns only records where all rows match

I have a query with a join on three tables. one of the columns in the 3rd table has a boolean value. . table 2 and table 3 are connected with product_id, each product_id on table 3 can be associated with true and false value as received value. I need a query to return all records in table 1 where are associated with products which their received value in table 3 has only true value.
In the sample data below I want to only return GHI
Table 1 - Sale
ID sale#
1 ABC
2 DEF
3 GHI
Table 2 PO Table 1 join Table 2 on Table1.ID = Table 2.SaleID
ID SaleID
1 1
2 1
3 2
4 3
5 3
Table 3
ID POID Received Table 2 right join table 3 on Table 2.ID = Table 3.POID
1 1 True
2 1 False
3 2 True
4 3 False
5 4 True
6 5 True
7 5 True
After the afternoon experimenting I make it work using a NOT IN, but it is very slow with my data set (which is only about 2000 records currently) I think it is probably because it is having to recreate the joins. It seems like there should be a more elegant way to accomplish this.
SELECT Distinct Table1.id, Table3.received
FROM Table3 INNER JOIN (Table2 INNER JOIN Table1 ON Table2.saleID = Table1.id)
ON Table3.POID = Table2.id
WHERE ((Table3.received)=True) and Table1.id NOT IN (
SELECT Table1.id
FROM Table3 INNER JOIN (Table2 INNER JOIN Table1 ON Table2.saleID = Table1.id)
ON Table3.POID = Table2.id
WHERE ((Table3.received)=False));
I believe this is the query you need
select
Table1.*
from
Table1 join Table2 on Table1.id = Table2.saleid
join table3 on table3.POID = Table2.ID
where
table3.received = true
first, only products have to be selected from table 3 that has true value entry in table3, this can be done by self join on POID. then the result can be joined with table2 and table1
select
Table1.*
from
Table1 join Table2
on Table1.id = Table2.saleid
join
(select t3.poid
from
Table3 t3 join Table3 t4
on t.POID = Table4.POID)
where t3.received = true and t4.received = true) all_true
on all_true.POID = Table2.ID
All you need to do is make sure that the count of records for a particular sale# is equal to the count of records with a value of received = True a.k.a. a count-if (which doesn't explicitly exist in SQL). The way you accomplish a count-if in SQL is to do a ...sum(case ... when ... then 1 else 0 end)....
Sample Data Setup:
create table dbo.Sale
(
ID int
, sale# char(3)
)
create table dbo.PO
(
ID int
, SaleID int
)
create table dbo.Received
(
ID int
, POID int
, Received char(5)
)
insert into dbo.Sale
values (1, 'ABC'), (2, 'DEF'), (3, 'GHI')
insert into dbo.PO
values (1,1), (2,1), (3,2), (4,3), (5,3)
insert into dbo.Received
values (1, 1, 'True')
, (2, 1, 'False')
, (3, 2, 'True')
, (4, 3, 'False')
, (5, 4, 'True')
, (6, 5, 'True')
, (7, 5, 'True')
Answer:
; with base as
(
select s.sale#
, p.SaleID
, r.POID
, r.Received
from dbo.Sale as s
inner join dbo.PO as p on s.ID = p.SaleID
inner join dbo.Received as r on p.ID = r.POID
)
, all_true as
(
--this sub-query is the filter for Sale#'s of interest
select b.sale#
from base as b
group by b.sale#
having sum(case b.Received when 'True' then 1 else 0 end) = count(*) --count-if = count
)
select b.*
from base as b
inner join all_true as t on b.sale# = t.sale#
Output:
+-------+--------+------+----------+
| sale# | SaleID | POID | Received |
+-------+--------+------+----------+
| GHI | 3 | 4 | True |
| GHI | 3 | 5 | True |
| GHI | 3 | 5 | True |
+-------+--------+------+----------+
Thanks tarheel
you put me on the track. I made the True/false a bit and added where Sum(received)= count(received)
SELECT DISTINCT Table1.id
FROM Table3 INNER JOIN (Table2 INNER JOIN Table1 ON Table2.saleID = Table1.id) ON Table3.POID = Table2.id
GROUP BY Table1.id
HAVING (-1*(Sum(Table3.received))=Count([Table3].[received]));

How do I convert old join line of code to new join syntax?

There is a section of code in one of my sqls that goes like this:
FROM
Table1
LEFT OUTER JOIN
TABLE2
ON (Table1.Field1 = Table2.Field1))
LEFT OUTER JOIN
TABLE3
ON(Table2.Field1 = Table3.Field1))
LEFT OUTER JOIN
Table4
ON(Table3.Field1 = Table4.Field1))
LEFT OUTER JOIN
Table5
ON(Table4.Field1= Table5.Field1)
Table6.Field1(+) = 'Y' (How do I convert this?)
I understand this is a right outer join, what would the syntax be updated to today's modern syntax?
Edit1: Updated to show more of the query. I've converted all the other joins, just missing the last line to be converted.
(+) was used to indicate an outer join in the sense that unmatched rows are also allowed. However the snippet you have shared with us does not contain enough information about "table6"
Based on the progression of joins t1 to t2, t2 to t3, t3 to t4, t4 to t5, my guess would be t5 to t6, like this:
FROM Table1
LEFT OUTER JOIN TABLE2 ON Table1.Field1 = Table2.Field1
LEFT OUTER JOIN TABLE3 ON Table2.Field1 = Table3.Field1
LEFT OUTER JOIN Table4 ON Table3.Field1 = Table4.Field1
LEFT OUTER JOIN Table5 ON Table4.Field1 = Table5.Field1
LEFT OUTER JOIN Table6 ON Table5.Field1 = Table6.Field1
AND Table6.Field1 = 'Y'
CREATE TABLE Table1 (TBL VARCHAR2(2), FIELD1 VARCHAR2(1));
INSERT INTO Table1 (tbl, field1) VALUES ('t1', 'y');
INSERT INTO Table1 (tbl, field1) VALUES ('t1', 'n');
INSERT INTO Table1 (tbl, field1) VALUES ('t1', 'y');
INSERT INTO Table1 (tbl, field1) VALUES ('t1', 'n');
CREATE TABLE Table6 (TBL6 VARCHAR2(2), FIELD1 VARCHAR2(1));
INSERT INTO Table6 (tbl6, field1) VALUES ('t6', 'y');
INSERT INTO Table6 (tbl6, field1) VALUES ('t6', 'n');
INSERT INTO Table6 (tbl6, field1) VALUES ('t6', 'y');
INSERT INTO Table6 (tbl6, field1) VALUES ('t6', 'n');
OLD SYNTAX
select table1.tbl, table1.field1, table6.tbl6, table6.field1 as t6_field1
from table1, table6
where table1.field1 = table6.field1(+)
and table6.field1(+) = 'y';
TBL | FIELD1 | TBL6 | T6_FIELD1
:-- | :----- | :--- | :--------
t1 | y | t6 | y
t1 | y | t6 | y
t1 | y | t6 | y
t1 | y | t6 | y
t1 | n | null | null
t1 | n | null | null
NEW SYNTAX
select table1.tbl, table1.field1, table6.tbl6, table6.field1 as t6_field1
from table1
left join table6 on table1.field1 = table6.field1
and table6.field1 = 'y';
TBL | FIELD1 | TBL6 | T6_FIELD1
:-- | :----- | :--- | :--------
t1 | y | t6 | y
t1 | y | t6 | y
t1 | y | t6 | y
t1 | y | t6 | y
t1 | n | null | null
t1 | n | null | null
dbfiddle here

Comparing 3 SQL Tables

I am trying to compare 3 tables with 1 being the base table.
So here are my 3 table(s) where Table 1 is the base table and the other two are compared with each other.
Table1
ID | ChargeItem
-----------------
5055 | Item1
5056 | Item2
5057 | Item3
5058 | Item4
5059 | Item5
5060 | Item6
5061 | Item7
5062 | Item8
5063 | Item9
5064 | Item10
5065 | Item11
Table2
ID | membershiprecordid | ChargeItemID | Status
-----------------------------------------------
1 | 268765 | 5060 | 1
2 | 268765 | 5060 | 1
Table3
ID | ChargeItemID
--------------------
12146 | 5058
12146 | 5060
12146 | 5062
12146 | 5063
12146 | 5065
Here is my SQL query so far
SELECT Table1.ID
FROM Table1 as T1
WHERE T1.ID NOT in (
select Table2.chargeitemid from Table2 as T2
right join Table3 as T3 on T2.chargeitemid = T3.chargeitemid
where T2.membershiprecordid = 268765 AND T2.[Status] = 2
)
So In the SQL query I am trying to get back IDs from Table 1 where it doesn't exist in Table 2 and Table 3. And Inside my sub query I compare Table 2 and Table 3 where by Table 2 taking priority over Table 3 so if a ChargeItemID exists in Table 2 with Status = 2 then fetch it and return its ID along with the ID's in the Table1
Currently it doesn't return any ID's for Table 1? Any suggestions as to why?
The Result should be the following ChargeItem ID's returned from Table1
5055,
5056,
5057,
5059,
5061,
5064
Hopefully it explains my issue?
Thanks
UPDATE
Please ignore T2.ClubID = 1600 it was posted in error
UPDATE 2
Expected result from the query
Try using below query to find out id's which are present on Table1 and not present on Table2 & table 3.
CREATE TABLE TABLE1 (ID INT);
INSERT INTO TABLE1 VALUES (5055), (5056), (5060), (5065), (5057);
CREATE TABLE TABLE2 (ID INT, CHARGEITEMID INT, STATUS INT)
INSERT INTO TABLE2 VALUES (1, 5060,1)
INSERT INTO TABLE2 VALUES (2, 5065,1)
INSERT INTO TABLE2 VALUES (2, 5056,2)
CREATE TABLE TABLE3 (ID INT, CHARGEITEMID INT )
INSERT INTO TABLE3 VALUES (1, 5058)
INSERT INTO TABLE3 VALUES (1, 5060)
INSERT INTO TABLE3 VALUES (1, 5062)
INSERT INTO TABLE3 VALUES (1, 5063)
INSERT INTO TABLE3 VALUES (1, 5065)
INSERT INTO TABLE3 VALUES (1, 5056)
select * from TABLE1
select * from TABLE2
select * from TABLE3
select id
from TABLE1
except
(
select CHARGEITEMID from TABLE2
intersect
select CHARGEITEMID from TABLE3
)
Can you see if this accomplish your request (Maybe I didn't understood it very well):
SELECT T1.ID
FROM Table1 as T1
LEFT JOIN (select DISTINCT T3.chargeitemid, T2.STATUS
from Table2 as T2
right join Table3 as T3 on T2.chargeitemid = T3.chargeitemid
) T4 ON T1.ID = T4.CHARGEITEMID
WHERE T4.chargeitemid IS NULL
OR T4.Status = 2
Sample data:
CREATE TABLE TABLE1 (ID INT);
INSERT INTO TABLE1 VALUES (5055), (5056), (5060), (5065), (5057);
CREATE TABLE TABLE2 (ID INT, CHARGEITEMID INT, STATUS INT)
INSERT INTO TABLE2 VALUES (1, 5060,1)
INSERT INTO TABLE2 VALUES (2, 5065,1)
INSERT INTO TABLE2 VALUES (2, 5056,2)
CREATE TABLE TABLE3 (ID INT, CHARGEITEMID INT )
INSERT INTO TABLE3 VALUES (1, 5058)
INSERT INTO TABLE3 VALUES (1, 5060)
INSERT INTO TABLE3 VALUES (1, 5062)
INSERT INTO TABLE3 VALUES (1, 5063)
INSERT INTO TABLE3 VALUES (1, 5065)
INSERT INTO TABLE3 VALUES (1, 5056)
Output:
ID
-----------
5055
5056
5057
A few things:
You mention: "where by Table 2 taking priority over Table 3." If you are performing a RIGHT JOIN, you are essentially saying that Table 3's rows should be shown regardless of whether there is a match in Table 2. Here, "RIGHT" indicates the table you are joining to, which is Table 3.
When you include a WHERE clause and a RIGHT JOIN, you are essentially negating the RIGHT JOIN and turning this query into an INNER JOIN. What does this mean? Your query will JOIN on the specified columns, then filter the entire search set to match your WHERE clause.
If you want all columns from Table 2 to be shown when they match the WHERE clause credentials regardless of whether the table can be joined to Table 3, you'll want to change your sub-query to:
SELECT Table2.chargeitemid from Table2 as T2
LEFT JOIN Table3 as T3
ON T2.chargeitemid = T3.chargeitemid
AND T2.clubid = 1600
AND T2.membershiprecordid = 268765
AND T2.[Status] = 2
This query will return all columns from Table 2 where the (T2.clubid = 1600 ...) are met and only show columns from table 3 if the chargeitemid is matched. This would accomplish "Table 2 taking priority over Table 3."
In addition, does your sub-query (the query inside WHERE T1.ID NOT in) return the expected results? I can update this post as needed.
You can do that with a left join, that will preserve all rows from Table1 and give null to the columns of Table2 and Table3 that are not joined. This way you only need to filter on those fields being null.
select t1.id
from Table1 t1
left join
Table2 t2
on t1.ID = t2.ChargeItemID and
t2.membershiprecordid = 268765 and
t2.[Status] = 2
left join
Table3 t3
on t1.ID = t3.ChargeItemID
where t2.ChargeItemID is null or
t3.ChargeItemID is null
If, as per #BeanFrog comment, you want the IDs that are not available on neither Table2 nor Table3, you can just replace OR with AND in the where clause.
Edit
Seems I misunderstood the requirements, this one should do the trick
select t1.id
from Table1 t1
left join
Table3 t3
on t1.ID = t3.ChargeItemID
left join
Table2 t2
on t3.ChargeItemID = t2.ChargeItemID
where t3.ChargeItemID is null or (
coalesce(t2.membershiprecordid, -1) = 268765 and
coalesce(t2.[Status], -1) = 2
);
This will return the IDs that are not in t3 or that are in both t3 and t2 (with the t2 filters applied); you can see it in action here
try to use not exists, like this
select T1.ID as cid
from Table1 as T1
where not exists (select 1 from Table2 as T2 where T2.chargeitemid = T1.ID)
and not exists
(select 1 from Table3 as T3 where T3.chargeitemid = T1.ID)
union all
select T2.chargeitemid as cid
from Table2 as T2
right join Table3 as T3 on T2.chargeitemid = T3.chargeitemid
where T2.membershiprecordid = 268765
and T2.Status = 2
Finally got this resolved by Using SQL Except as shown below. So in the query it queries the master table first and gets all the id's. Then I compare the results against the results from table 2 and table 3 to get the final list.
SELECT id FROM table1
except
SELECT chargeitemid FROM table3
except
SELECT chargeitemid FROM table2 WHERE membershiprecordid = 268765 AND status = 2

outer join more than 1 table

let's say I have 5 tables, as follows:
CREATE TABLE T1 (
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY NUMERIC,
SALARY NUMERIC);
CREATE TABLE T2 (
CITY NUMERIC,
DISTRICT NUMERIC);
CREATE TABLE T3 (
DISTRICT NUMERIC,
DOMAIN NUMERIC);
CREATE TABLE T4 (
DOMAIN NUMERIC,
DETAILS_BOOK NUMERIC);
CREATE TABLE T5 (
DETAILS_BOOK NUMERIC,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
EMAIL VARCHAR2(100));
INSERT INTO T1 VALUES ('john', 'doe',1001,1000);
INSERT INTO T1 VALUES ('jack', 'jill',1001,2000);
INSERT INTO T1 VALUES ('jeff', 'bush',1001,1500);
INSERT INTO T2 VALUES (1001,1);
INSERT INTO T3 VALUES (1,543);
INSERT INTO T4 VALUES (543,22);
INSERT INTO T5 VALUES (22,'john', 'doe','john#22.com');
INSERT INTO T5 VALUES (44,'john', 'doe','john#44.com');
INSERT INTO T5 VALUES (22,'jeff', 'bush','jeff#22.com');
INSERT INTO T5 VALUES (44,'jeff', 'bush','jeff#44.com');
now, I want all records from t1, with their salaries and emails, corresponding to tables t2, t3, and t4, such that the reuslt should be:
FIRST_NAME | LAST_NAME | SALARY | EMAIL
--------------------------------------------------
john | doe | 1000 | john#22.com
jeff | bush | 1500 | jeff#22.com
jack | jill | 2000 | (NULL)
what I got so far is:
SELECT T1.FIRST_NAME, T1.LAST_NAME,T1.SALARY,T5.EMAIL
FROM T1,T2,T3,T4,T5
WHERE T1.FIRST_NAME = T5.FIRST_NAME (+)
and T1.LAST_NAME = T5.LAST_NAME(+)
AND T1.CITY = T2.CITY
AND T2.DISTRICT = T3.DISTRICT
AND T3.DOMAIN = T4.DOMAIN
AND T4.DETAILS_BOOK = T5.DETAILS_BOOK
which returns only the first two rows.
Try this instead:
SELECT
T1.FIRST_NAME,
T1.LAST_NAME,
T1.SALARY,
T5.EMAIL
FROM T1
LEFT JOIN T2 ON T1.CITY = T2.CITY
LEFT JOIN T3 ON T2.DISTRICT = T3.DISTRICT
LEFT JOIN T4 ON T3.DOMAIN = T4.DOMAIN
LEFT JOIN T5 ON T4.DETAILS_BOOK = T5.DETAILS_BOOK
AND T1.FIRST_NAME = T5.FIRST_NAME
AND T1.LAST_NAME = T5.LAST_NAME;
SQL Fiddle Demo
This will give you:
| FIRST_NAME | LAST_NAME | SALARY | EMAIL |
-------------------------------------------------
| john | doe | 1000 | john#22.com |
| jeff | bush | 1500 | jeff#22.com |
| jack | jill | 2000 | (null) |
The problem is that the INNER JOIN after the OUTER JOIN makes your joins works like an INNER , because, the inner joins eliminate those unmatched rows coming from the outer joins.
Note that: I used the ANSI SQL-92 explicit LEFT OUTER JOIN syntax, instead of the old implicit OUTER and INNER join syntax that you sued in your query.
Please try to use the LEFT OUTER JOIN instead of the old outer join syntax, and avoid INNER JOIN after OUTER JOINs.
For more details, see these:
Bad habits to kick : using old-style JOINs..
Bad habits to kick : using table aliases like (a, b, c) or (t1, t2, t3)
Update:
When you have many tables references in the FROM clause with the JOIN between them, each table is joined with the next table begging from the FROM clause1, results a temporary result set, then this temporary result set is joined with the next table and so on. In case of the OUTER JOIN, there are left or right:
LEFT JOIN will include those unmatched rows from the left table, where as,
RIGHT JOIN will include those unmatched rows from the right table.
Depending on the data you want to select, you have to watch out those tables in the two sides of the JOIN operator and the order of them.
1:This is just the logical query processing order, but in the actual order is always up to the query optimizer.