Select multiple columns from another table depending on value of column - sql

I'm not even sure this is possible, but I have an order table (online store). Within this table, the shipping and billing address columns are ID's which correspond with the address table.
For E.g.
OrderID ShippingAddressID BillingAddressID
201800194 21183 21182
The Address table then lists the address information.
AddressID Address1 City RegionCode
21182 123 Somewhere Dr Hometown1 Florida
21183 456 Elsewhere Rd Hometown2 Florida
I'd like the resulting listing to show something similar to this:
OrderID BillingAddress1 BillingCity BillingRegionCode ShippingAddress1 ShippingCity ShippingRegionCode
201800194 123 Somewhere Dr Hometown1 Florida 456 Elsewhere Rd Hometown2 Florida
Is this even possible?
Thanks..

Join the address table twice. Example with your data below.
CREATE TABLE #Orders (OrderID int, ShippingAddressId int, BillingAddressId int)
CREATE TABLE #Address (AddressID int, Address1 varchar(100), City varchar(100), RegionCode varchar(100))
INSERT INTO #Orders (OrderID, ShippingAddressId, BillingAddressId) VALUES
(201800194 , 21183, 21182)
INSERT INTO #Address (AddressID, Address1, City, RegionCode) VALUES
(21182, '123 Somewhere Dr', 'Hometown1', 'Florida'),
(21183, '456 Elsewhere Rd', 'Hometown2', 'Florida')
SELECT
ORD.OrderID,
BILL.Address1 AS 'BillingAddress1',
BILL.City AS 'BillingCity',
BILL.RegionCode AS 'BillingRegionCode',
SHIP.Address1 AS 'ShippingAddress1',
SHIP.City AS 'ShippingCity',
SHIP.RegionCode AS 'ShippingRegionCode'
FROM
#Orders AS ORD
LEFT OUTER JOIN #Address AS SHIP
ON ORD.ShippingAddressId = SHIP.AddressID
LEFT OUTER JOIN #Address AS BILL
ON ORD.BillingAddressId = BILL.AddressID
DROP TABLE #Orders
DROP TABLE #Address

Lets assume your Tables are Order, Address.
Select A.OrderID, B1.Address1 As 'BillingAddress1', B1.City As 'BillingCity', B1.RegionCode As 'BillingRegionCode', B2.Address1 As 'ShippingAddress1', B2.City As 'ShippingCity', B2.RegionCode As 'ShippingRegionCode'
FROM Order AS A
Left Join Address AS B1 On A.BillingAddressID = B1.AddressID
Left Join Address As B2 On A.ShippingAddressID = B2.AddressID
Hope this Helps

Yes you can achieve it using join like this -
SELECT OrderId, Billing.Address1 As BillingAddress1, Shipping.Address1 AS
ShippingAddress1, ... other column
FROM dbo.Order
LEFT JOIN dbo.Address AS Billing ON Order.BillingAddressID = Billing.AddressID
LEFT JOIN dbo.Address AS Shipping ON Order.ShippingAddressID = Shipping.AddressID

Related

How to use write a SQL join when there exists empty cell in the join column?

Schema:
CREATE TABLE PRODUCT
(
PRODUCTID INT,
PRODUCTNAME VARCHAR(100),
PRODUCTUSER VARCHAR(100)
);
CREATE TABLE USER
(
USERID INT,
USERNAME VARCHAR(100),
USEREMAIL VARCHAR(100)
);
INSERT INTO PRODUCT(PRODUCTID,PRODUCTNAME,PRODUCTUSER)
VALUES (1, 'Product1', 'Chen'), (2, 'Product2', 'Bob'),
(3, 'Product3', ''), (4, 'Product4', '');
INSERT INTO USER (USERID, USERNAME, USEREMAIL)
VALUES (1, 'Chen', 'chen#email.com'),
(2, 'Bob', 'bob#email.com'),
(3, 'Paul', 'paul#email.com'),
(4, '', ''), (5, '', '');
Product table:
ProductID ProductName ProductUser
------------------------------------
1 Product1 Chen
2 Product2 Bob
3 Product3
4 Product4
User table:
UserID UserName UserEmail
--------------------------------
1 Chen chen#email.com
2 Bob bob#email.com
3 Paul paul#email.com
4
5
I want to join Product and User table to get all the Product Names and the User name (if available) as output. The challenge is that the common field Product.ProductUser and User.UserName both contain empty values as shown in example above. I know this is not a good schema design but I am cannot change the schema as it is out of my control.
Expected output:
PROCUTNAME USERNAME
----------------------
Product1 Chen
Product2 Bob
Product3
Product4
Sample query 1:
SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
JOIN USER U
ON P.PRODUCTUSER=U.USERNAME
Above query is an inner join so returns duplicates for Product3 and Product4 due to the join on empty. Adding a WHERE clause ProductUser<>'' results in exclusion of Product3 and Product4.
Usually if the ProductUser were NULL instead of empty then I know that a LEFT JOIN would be the solution. I think that I understand the difference between using the criteria in the ON clause and WHERE clause of the LEFT JOIN.
So trying a left join with criteria in the ON clause:
SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
LEFT JOIN USER U
ON P.PRODUCTUSER=U.USERNAME AND P.PRODUCTUSER<>''
So the above query works by 1st doing an inner join based on the given criteria in ON clause, and then pulls in all other rows from the product table and puts a null for username. (or in other words it first lists all products, and then joins on those records that satisfy the ON criteria.)
This gives me output as expected. But I am not sure whether my approach is correct so trying another approach:
SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
LEFT JOIN (SELECT * FROM USER WHERE USERNAME<>'') U
ON P.PRODUCTUSER=U.USERNAME
This also works.
Is the left join with criteria in the ON clause a correct way to approach the problem?
Can you just do a group by to remove the duplicates?
declare #prod TABLE (PRODUCTID INT, PRODUCTNAME VARCHAR(100), PRODUCTUSER VARCHAR(100));
declare #user table (USERID INT, USERNAME VARCHAR(100),USEREMAIL VARCHAR(100));
INSERT INTO #prod(PRODUCTID,PRODUCTNAME,PRODUCTUSER) values (1,'Product1','Chen'),
(2,'Product2','Bob'),(3,'Product3',''),(4,'Product4','');
INSERT INTO #user(USERID,USERNAME,USEREMAIL) VALUES (1,'Chen','chen#email.com'),
(2,'Bob','bob#email.com'),(3,'Paul','paul#email.com'),
(4,'',''),(5,'','');
select * from #prod
select * from #user
select
p.ProductId,
p.ProductName,
u.USERNAME
FROM #prod p
left join #user u on p.PRODUCTUSER = u.USERNAME
group by
p.PRODUCTID,
p.PRODUCTNAME,
u.USERNAME
select
main.PRODUCTNAME
, case
when sub.USERNAME is null
then ''
else sub.USERNAME
end USERNAME
from #PRODUCT main
left join
#USER sub
on main.PRODUCTUSER = sub.USERNAME
and sub.USERNAME like '%[A-Za-z]%'

Sql query to find select customer that bought in the specific company address

Here is my table
CREATE TABLE Customer
(
ID CHAR(50),
Customer_FName CHAR(50),
Customer_Lname CHAR(50)
);
CREATE TABLE Buying
(
Customer_ID CHAR(50),
Product_ID CHAR(50),
Order_Time CHAR(50)
);
CREATE TABLE Product
(
ID CHAR(50),
Name CHAR(50),
Address CHAR(50)
);
I am trying to find all customers who bought a product with their company's address in 'Burwood' and list the customer's ID, names, product ID, product name and product address
Select
Buying.Customer_ID, Buying.Product_ID, Product.ID,
Product.Name, Customer.ID,
Customer.Customer_FName, Customer.Customer_Lname
from
((Buying
inner join
Product on Buying.Product_ID = Product.ID)
inner join
Customer on Buying.Customer_ID = Customer.ID)
where
Product.Address like '%Burwood%';
I want to combine three table but It shows 'no rows selected'.
I also give a sample data table
Any reason why you have chosen CHAR as the datatype for all columns of all tables? For CHAR based columns, DBs tend to pad the values up to the column width defined. That said, it is not why you are not getting result. You may want to check if during insert you are adding any extra space or non-printable characters in IDs resulting into failed inner joins.
I suggest change the fields to VARCHAR instead, validate your inserts and then query just as I demonstrated below. You will start getting result, as I am..
CREATE TABLE Customer (
ID varchar(50),
Customer_FName varchar(50),
Customer_Lname varchar(50)
);
CREATE TABLE Buying (
Customer_ID varchar(50),
Product_ID varchar(50),
Order_Time varchar(50)
);
CREATE TABLE Product (
ID varchar(50),
Name varchar(50),
Address varchar(50)
);
insert into customer values('10001', 'John', 'Smith');
insert into Buying values('10001', '772', '2016/09/01');
insert into Product values('772', 'Telephone', '22 Ave, Burwood');
select b.product_id, p.name, b.customer_id, c.customer_fname, c.customer_lname
from buying b
join product p on b.product_id = p.id
join customer c on b.customer_id = c.id
where lower(p.address) like '%burwood%'
Please try this, it works for me:
Select B.Customer_ID, B.Product_ID, P.ID, P.Name, C.ID, C.Customer_FName, C.Customer_Lname
from Buying B
INNER JOIN Product P ON B.Product_ID = P.ID
INNER JOIN Customer C ON B.Customer_ID = C.ID
WHERE P.Address LIKE '%Burwood%'
Try this:
SELECT C.*,B.*, P.*
FROM Customer C,Buying B, Product P
WHERE B.Product_ID=P.ID
AND B.Customer_ID=C.ID
AND P.Address LIKE '%Burwood%';

Simple SQL query from table

For my CIS class, I have SQL project, and this is the first time I'm working with SQL, doing okay but I can't do one of the queries. Any help would be greatly appreciated.
This is what I tried:
Select cno, cname
from customer
where
)
)
)
Just use two IN clauses, one for 'Financial Accounting', one for 'Cost Accounting'.
Select cno, cname
from customer
where cno in
(
select cno
from salesorder
where ono in
(
select ono
from orderline
where bno in (select bno from book where bname = 'Financial Accounting')
)
)
and cno in
(
select cno
from salesorder
where ono in
(
select ono
from orderline
where bno in (select bno from book where bname = 'Cost Accounting')
)
);
Rob M's solution is more elegant, whereas above query should be more along the lines what you've learned so far.
You aren't exactly clear on whether the customer needs to have ordered both books in one order or across multiple orders. I'll assume the latter, based on the data provided.
Your answer returns customers who ordered either (or both) of those books. You say you want customers who order both books. Also, it's hard to keep your code straight when nesting several subqueries. Most people prefer joins.
This query should work for you.
select cno,cname from customer where cno in (
select o.cno
from salesorder o
inner join orderline ol on o.ono=ol.ono
inner join book b on b.bno=ol.bno
where b.bname in ('Financial Accounting', 'Cost Accounting')
group by o.cno
having count(distinct b.bno) = 2 -- Require both separate books, not 2 of one book or the other
)
Here is a complete example in SQL Server:
declare #book table (bno int, bname varchar(50))
insert #book (bno,bname) values
(10501,'Forensic Accounting')
,(10704,'Financial Accounting')
,(10933,'Cost Accounting')
declare #orderline table (ono int, bno int)
insert #orderline (ono,bno) VALUES
(1020,10501)
,(1020,10502)
,(1020,10503)
,(1020,10504)
,(1021,10605)
,(1022,10605)
,(1022,10704)
,(1023,10879)
,(1023,10988)
,(1024,10502)
,(1024,10988)
,(1026,10933)
,(1027,10933)
,(1028,10933)
,(1028,10965)
,(1029,10933)
,(1029,10965)
,(1029,10988)
,(1030,10965)
declare #salesorder table (ono int, cno int)
insert #salesorder (ono,cno) VALUES
(1020,23511)
,(1021,23513)
,(1022,23513)
,(1023,23512)
,(1024,23511)
,(1025,23511)
,(1026,23511)
,(1027,23512)
,(1028,23512)
,(1029,23513)
,(1030,23511)
declare #customer table (cno int, cname varchar(20))
insert #customer (cno,cname) values
(23511,'a')
,(23512,'b')
,(23513,'c')
,(23514,'d')
,(23515,'e')
,(23516,'f')
,(23517,'g')
,(23518,'h')
select cno,cname from #customer where cno in (
select o.cno
from #salesorder o
inner join #orderline ol on o.ono=ol.ono
inner join #book b on b.bno=ol.bno
where b.bname in ('Financial Accounting', 'Cost Accounting')
group by o.cno
having count(distinct b.bno) = 2 -- Require both separate books, not 2 of one book or the other
)

SQL Simple SELECT Query

create table Person(
SSN INT,
Name VARCHAR(20),
primary key(SSN)
);
create table Car(
PlateNr INT,
Model VARCHAR(20),
primary key(PlateNr)
);
create table CarOwner(
SSN INT,
PlateNr INT,
primary key(SSN, PlateNR)
foreign key(SSN) references Person (SSN),
foreign key(PlateNr) references Car (PlateNr)
);
Insert into Person(SSN, Name) VALUES ('123456789','Max');
Insert into Person(SSN, Name) VALUES ('123456787','John');
Insert into Person(SSN, Name) VALUES ('123456788','Tom');
Insert into Car(PlateNr, Model) VALUES ('123ABC','Volvo');
Insert into Car(PlateNr, Model) VALUES ('321CBA','Toyota');
Insert into Car(PlateNr, Model) VALUES ('333AAA','Honda');
Insert into CarOwner(SSN, PlateNr) VALUES ('123456789','123ABC');
Insert into CarOwner(SSN, PlateNr) VALUES ('123456787','333AAA');
The problem I'm having is the SELECTE query I wanna make. I wan't to be able to SELECT everything from the Person and wan't the include the PlateNr of the car he's the owner of, an example:
PERSON
---------------------------------
SSN NAME Car
123456789 Max 123ABC
123456787 John 3338AAA
123456788 Tom
----------------------------------
So, I want to be able to show everything from the Person table and display the content of CarOwner aswell if the person is in fact a CarOwner. What I have so far is: "SELECT * from Person, CarOwner WHERE Person.SSN = CarOwner.SSN;". But this obviously results in only showing the person(s) that are CarOwners.
Hope I explained me well enough, Thanks.
Try this:
SELECT p.*, c.*
FROM Person p
LEFT OUTER JOIN CarOwner co
ON p.SSN = co.SSN
LEFT OUTER JOIN Car c
ON co.PlateNr = c.PlateNr
Show SQLFiddle
P.S. I've changed the type of your primary key PlateNr (in varchar and not in int)
select ssn, name, car
from Person p
LEFT OUTER JOIN CarOwner co
ON p.SSN = co.SSN
LEFT OUTER JOIN Car c
ON co.PlateNr = c.PlateNr

SQL Cross Join with null values

I have a table AddressTypes with 4 records (home,office,vacation,hotel) and a table Address that share the filed addresstypeid.
In address table I have 1 record of type "home" and I want a query where I get 4 rows like this:
Type Address1 Address2 City State
home piping 1232 Austin Tx
office null null null null
vacation null null null null
hotel null null null null
Here is an image of tables: http://tinypic.com/view.php?pic=28078xv&s=6
I'm sure is something very easy maybe using cross join but don't get it. Hope someone can guide me. Appreciate in advance.
Left joining AdddressTypes to Addresses will produce desired result:
select at.Type,
a.Address1,
a.Address2,
a.City,
a.State
from AddressTypes at
left join Address a
on at.AddressTypeID = a.AddressTypeID
-- For this query to make sense
-- Filter one person only
and a.PersonID = #PersonID
----------- THIS PART WAS ADDED BY VAAA ------------------------
Nikola, I change to this:
select at.description,
a.Address1,
a.Address2,
a.City
from address_types at
left join Address a
on 1 = 1
-- For this query to make sense
-- Filter one person only
and a.addressid = 24
And then I get the 4 rows, but all of them have the same address info and just the "home" type address is the one with data. So its close...
Use the LEFT OUTER JOIN, which returns one copy of matching records from both the left and right tables and non-matching records from both the tables. Here is the test code I tried:
CREATE TABLE AddressTypes(
AddressType SMALLINT NOT NULL,
[Description] NVARCHAR(50))
ALTER TABLE AddressTypes
ADD CONSTRAINT PK_AddressTypes_AddressType
PRIMARY KEY (AddressType)
CREATE TABLE [Address] (
AddressID INT NOT NULL,
AddressType SMALLINT,
Address1 NVARCHAR(50),
Address2 NVARCHAR(50),
City NVARCHAR(50),
State CHAR(2))
ALTER TABLE [Address]
ADD CONSTRAINT PK_Address_AddressID
PRIMARY KEY (AddressID)
ALTER TABLE [Address]
ADD CONSTRAINT FK_address_addresstypes_addresstype
FOREIGN KEY (AddressType) REFERENCES AddressTypes(AddressType)
INSERT INTO AddressTypes VALUES (1, 'home'), (2, 'office'),
(3, 'vacation'), (4, 'hotel')
INSERT INTO address VALUES (1, 1, 'piping', '1232', 'Austin', 'TX')
-- Here is the query that outputs the result set.
SELECT AT.AddressType AS [Type], A.Address1, A.Address2, A.City, A.State
FROM AddressTypes AT
LEFT OUTER JOIN address A
ON AT.AddressType = A.AddressType