Getting values from multiple tables in one column - sql

Let's say I have three tables:
table orders:
invoice_ID
customer_ID
202201
1000
202202
2000
202203
3000
202204
4000
table department_north
customer_ID
product
price
4000
VW Rabbit
$5000.00
1000
BMW X5
$15.000
table department_south
customer_ID
product
price
3000
Tesla S
$30.000
2000
BMW X3
$20.000
Wanted Result
A table with invoice_id, a new column with all cars that contain '%BMW%', a new column with the attached price
invoice_ID
product_bmw
price_bmw
202201
BMW X5
$5.000
202202
BMW X3
$20.000
I figured out how to get the results for one department table but can't find a statement for both.
SELECT DISTINCT orders.invoice_ID,
department_north.product AS product_BMW,
department_north.price AS price_BMW
FROM orders
JOIN LEFT department_north
ON department_north.customer_ID = order.customer_id
JOIN LEFT department_south
ON department_south.customer_ID = order.customer_id
WHERE department_north.product LIKE '%BMW%'

I would UNION ALL all departments. See following example:
DECLARE #orders TABLE
(
invoice_ID varchar(20),
customer_ID int
);
INSERT #orders VALUES
(202201, 1000),
(202202, 2000),
(202203, 3000),
(202204, 4000);
DECLARE #department_north TABLE
(
customer_ID int,
product nvarchar(20),
price decimal(15,2)
);
INSERT #department_north VALUES
(4000, 'VW Rabbit', 5000),
(1000, 'BMW X5', 15000);
DECLARE #department_south TABLE
(
customer_ID int,
product nvarchar(20),
price decimal(15,2)
);
INSERT #department_south VALUES
(3000, 'Tesla S', 30000),
(2000, 'BMW X3', 20000);
WITH AllDepartments AS
(
SELECT *
FROM #department_north
UNION ALL
SELECT *
FROM #department_south
)
SELECT invoice_ID, product, price
FROM #orders O
JOIN AllDepartments D ON O.customer_ID=D.customer_ID
WHERE product LIKE '%BMW%';

I would use union all like Paweł Dyl's answer above, but would create a single department table and create an extra column, called location or similar and put an 'S' for south and an 'N' for north into it as per below:
create table #department
(
customer_ID int
, product varchar(64)
, price decimal(15,2)
, "location" varchar(64) -- to allow for other locations
)
;
insert into #department values (4000, 'VW Rabbit', 5000.00, 'N');
insert into #department values (1000, 'BMW X5', 15.000, 'N');
insert into #department values (3000, 'Tesla S', 30.000, 'S');
insert into #department values (2000, 'BMW X3', 20.000, 'S');
This means that you are just using the one department table and you have the additional 'location' column for adding east or west if need be. This will reduce the need to create a new database table for each new location added to your list. You could expand this to include city and/or state or whatever depending on the range of the data but you should aim to use only one table for this purpose.
Creating multiple tables based purely on location would not be recommended and think, what would you do if there were many locations e.g. 50 or more? It would be a nightmare to manage this code by creating a separate table for each location.

Related

SQL Data Manipulation (Adding FK and Displaying one Data from different table)

I'm new in SQL and we have an activity. I only have two problems in my query, first is adding the FK because when I run it, this will have an error that show like this: near "FOREIGN": syntax error and I don't know why.
Second is I dont know how to display the Products, Vendor ID and Name that comes from different table (This is the part of the instruction:
Determine which products have a quantity of less than 1000 then display the products Vendor ID and Name)
CREATE TABLE Products (ProductID int NOT NULL PRIMARY KEY, Description varchar (100), Quantity
int, Price int (50), VendorID int NOT NULL);
CREATE TABLE Vendors (VendorID int NOT NULL PRIMARY KEY, Name varchar (50), ContactNum int);
ALTER TABLE Products ADD FOREIGN KEY (VendorID) REFERENCES Vendors (VendorID);
INSERT INTO Vendors VALUES ('V00001', 'Universal Corporation','8633-76131');
INSERT INTO Vendors VALUES('V00002', 'Liwayway Corporation','8844-8441');
INSERT INTO Vendors VALUES ('V00003', 'Monde Nissin', '7759-5000');
Select * FROM Vendors;
INSERT INTO Products VALUES ('P000101', 'Jack N Jill Piattos', 1000, 15, 'V00001');
INSERT INTO Products VALUES ('P000102', 'Jack N Jill Nova', 1000, 15, 'V00001');
INSERT INTO Products VALUES ('P000105', 'Oishi Prawn Crackers', 700, 8, 'V00002');
INSERT INTO Products VALUES ('P000107', 'Nissin Eggnog Cookies', 850, 7, 'V00003');
SELECT * FROM Products;
UPDATE Products SET Quantity = Quantity + 274 WHERE ProductID = 'P000101';
UPDATE Products SET Quantity = Quantity - 42 WHERE ProductID = 'P000107';
SELECT * FROM Products;
SELECT DISTINCT ProductID, Description, Quantity FROM Products WHERE Quantity < 1000;

How to insert a record into a table - depending on the total requiredQty from another table?

I have this row in the database table:
ID requiredQty
1088 30
And another table:
ID orderLineID bookedInQty
3000 1088 10
3001 1088 10
dbfiddle: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=9ecd8c83fcda08453481ec6d0ce45947
Summary
Total booked in quantity is total of 20 and 10 remaining for that particular order-line.
Question
How can I create an if statement to insert a record into the 2nd table, not to exceed table 1 requiredQty: 30?
Example
If insert bookedInQty: 11 this means it exceeds 30 because there is an extra 1. If it exceeds, simply do nothing.
If to insert bookedInQty: 9 this does not exceeds 30 because the total now equals to 29. Then insert this record.
Note
Without creating any extra tables, I am trying to do it using an if statement.
This uses if to check if the sum of the bookedQty and the new value are lower then the required quantity. You can put the code in a stored procedure.
create table table1(
id int NOT NULL,
requiredQty int
);
create table table2(
id int NOT NULL,
orderLineId int,
bookedInQty int
);
insert into table1(id, requiredQty) VALUES (1088, 30);
insert into table2(id, orderLineId, bookedInQty)
VALUES
(3000, 1088, 10),
(3001, 1088, 10);
declare #sumQty int, #newQty int, #newOrderLineId int;
select #newOrderLineId = 1088, #newQty = 11; -- change #newQty to 10 or lower
select #sumQty = sum(bookedInQty) from table2 where orderLineId = #newOrderLineId
group by orderLineId;
-- I hardcoded the value of id, it should add 1 to the maximum value or use an identity column
if exists(select * from table1 where id = #newOrderLineId and requiredQty >= #sumQty + #newQty)
insert table2 (id, orderLineId, bookedInQty) values (3002, #newOrderLineId, #newQty);
select * from table1;
select * from table2;
Dbfiddle demo:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d800624279381f9bbd71cf51bbc5351a

SELECT From Multiple tables with many to many relations

Hello everyone I have inherirted a poorly designed database and I need to get some information from 3 tables
Franchise
Id(Int, PK)
FrID (varchar(50))
FirstName (varchar(50))
LastName (varchar(50))
Store
Id (Int, PK)
FrID (varchar(50))
StoreNumber (varchar(50))
StoreName
Address
Pricing
Id (int, PK)
StoreNumber (varchar(50))
Price1
Price2
Price3
and the data
ID, FrID ,FirstName,LastName
1, 10 ,John Q , TestCase
2, 10 ,Jack Q , TestCase
3, 11 ,Jack Q , TestCase
ID, FrID, StoreNumber , StoreName , Address
10, 10 , 22222 , TestStore1, 123 Main street
11, 10 , 33333 , TestStore2, 144 Last Street
12, 10 , 44444 , TestStore2, 145 Next Street
13, 11 , 55555 , Other Test, 156 Other st
ID, StoreNumber, Price1, Price2, Price3
1, 22222 , 19.99, 20.99 , 30.99
2, 33333 , 19.99, 20.99 , 30.99
3, 44444 , 19.99, 20.99 , 30.99
4, 55555 , 19.99, 20.99 , 30.99
Here is what I have done
SELECT F.FirstName,F.LastName,F.FrID , S.StoreNumber,S.StoreName,S.Address,
P.Price1,P.Price2,P.Price3
FROM Franchisee F
JOIN Store S on F.FrID = S.FrID
JOIN Pricing P on P.StoreNumber = S.StoreNumber
This part works, but I end up with lots of duplicates, For example Jack Q gets listed for his store plus every store that John Q is on. Is there anyway to fix this with out a database redesign.
Okay, there is a whole laundry list of issues such as character fields such as [FrId] being used as strings, reserved words such as [address] being used as name, etc.
Let's put the bad design issues aside.
First, I need to create a quick test environment. I did not put in Foreign Keys since that constraint is not needed to get the correct answer.
--
-- Setup test tables
--
-- Just playing
use Tempdb;
go
-- drop table
if object_id('franchise')> 0
drop table franchise;
go
-- create table
create table franchise
(
Id int primary key,
FrID varchar(50),
FirstName varchar(50),
LastName varchar(50)
);
-- insert data
insert into franchise values
( 1, 10, 'John Q', 'TestCase'),
( 2, 10, 'Jack Q', 'TestCase'),
( 3, 11, 'Jack Q', 'TestCase');
-- select data
select * from franchise;
go
-- drop table
if object_id('store')> 0
drop table store;
go
-- create table
create table store
(
Id int primary key,
FrID varchar(50),
StoreNumber varchar(50),
StoreName varchar(50),
Address varchar(50)
);
-- insert data
insert into store values
(10, 10, 22222, 'TestStore1', '123 Main street'),
(11, 10, 33333, 'TestStore2', '144 Last Street'),
(12, 10, 44444, 'TestStore2', '145 Next Street'),
(13, 11, 55555, 'Other Test', '156 Other Street');
-- select data
select * from store;
go
-- drop table
if object_id('pricing')> 0
drop table pricing;
go
-- create table
create table pricing
(
Id int primary key,
StoreNumber varchar(50),
Price1 money,
Price2 money,
Price3 money
);
-- insert data
insert into pricing values
(1, 22222, 19.99, 20.99 , 30.99),
(2, 33333, 19.99, 20.99 , 30.99),
(3, 44444, 19.99, 20.99 , 30.99),
(4, 55555, 19.95, 20.95 , 30.95);
-- select data
select * from pricing;
go
The main issue is that the franchise table should have the primary key (PK) on FrId, not Id. I do not understand why there are duplicates.
However, the query below removes them by grouping. I changed the pricing data for Jack Q to show it is a different record.
--
-- Fixed Query - Version 1
--
select
f.FirstName,
f.LastName,
f.FrID,
s.StoreNumber,
s.StoreName,
s.Address,
p.Price1,
p.Price2,
p.Price3
from
-- Remove duplicates from francise
(
select
LastName,
FirstName,
Max(FrID) as FrID
from
franchise
group by
LastName,
FirstName
) as f
join store s on f.FrID = s.FrID
join pricing p on p.StoreNumber = s.StoreNumber;
The correct output is below.
If I am correct, remove the duplicates entries and change the primary key.
Change Requirements
Okay, you are placing two or more owners in the same table.
Below uses a sub query to combine the owners list into one string. Another way is to have a flag called primary owner. Choose that as the display name.
--
-- Fixed Query - Version 2
--
select
f.OwnersList,
f.FrID,
s.StoreNumber,
s.StoreName,
s.Address,
p.Price1,
p.Price2,
p.Price3
from
-- Compose owners list
(
select
FrID,
(
SELECT FirstName + ' ' + LastName + ';'
FROM franchise as inner1
WHERE inner1.FrID = outer1.FrID
FOR XML PATH('')
) as OwnersList
from franchise as outer1
group by FrID
) as f (FrId, OwnersList)
join store s on f.FrID = s.FrID
join pricing p on p.StoreNumber = s.StoreNumber
Here is the output from the second query.

SQL Stored procedure to obtain top customers

I'm trying to create a stored procedure that goes through a "SALES" table and returns the best two customers of a pharmacy (the two customers who have spent more money).
Here's some code:
Table creation:
create table Customer (
Id_customer int identity(1,1) Primary Key,
Name varchar(30),
Address varchar(30),
DOB datetime,
ID_number int not null check (ID_number > 0),
Contributor int not null check (Contributor > 0),
Customer_number int not null check (Customer_number > 0)
)
create table Sale (
Id_sale int identity(1,1) Primary Key,
Id_customer int not null references Customer(Id_customer),
Sale_date datetime,
total_without_tax money,
total_with_tax money
)
Well, I don't know if this is useful but I have a function that returns the total amount spent by a customer as long as I provide the customer's ID.
Here it is:
CREATE FUNCTION [dbo].[fGetTotalSpent]
(
#Id_customer int
)
RETURNS money
AS
BEGIN
declare #total money
set #total = (select sum(total_with_tax) as 'Total Spent' from Sale where Id_customer=#Id_customer)
return #total
END
Can someone help me get the two top customers?
Thanks
Chiapa
PS: Here's some data to insert so you can test it better:
insert into customer values ('Jack', 'Big street', '1975.02.01', 123456789, 123456789, 2234567891)
insert into customer values ('Jim', 'Little street', '1985.02.01', 223456789, 223456789, 2234567891)
insert into customer values ('John', 'Large street', '1977.02.01', 323456789, 323456789, 3234567891)
insert into customer values ('Jenny', 'Huge street', '1979.02.01', 423456789, 423456789, 4234567891)
insert into sale values (1, '2013.04.30', null, 20)
insert into sale values (2, '2013.05.22', null, 10)
insert into sale values (3, '2013.03.29', null, 30)
insert into sale values (1, '2013.05.19', null, 34)
insert into sale values (1, '2013.06.04', null, 21)
insert into sale values (2, '2013.06.01', null, 10)
insert into sale values (2, '2013.05.08', null, 26)
You can do this with a single query without any special functions:
select top 2 c.id_customer, c.name, sum(s.total_with_tax)
from customer c
join sale s on c.id_customer = s.id_customer
group by c.id_customer, c.name
order by sum(s.total_with_tax) desc
This joins onto a CTE with the top customers.
Remove the WITH TIES option if you want exactly 2 and don't want to include customers tied with the same spend.
WITH Top2
AS (SELECT TOP 2 WITH TIES Id_customer,
SUM(total_with_tax) AS total_with_tax
FROM Sale
GROUP BY Id_customer
ORDER BY SUM(total_with_tax) DESC)
SELECT *
FROM Customer C
JOIN Top2 T
ON C.Id_customer = T.Id_customer
I'm not really into SQL Server dialect, but this one will give you best customers in descending order along with money they spent:
select Id_customer, total_with_tax from
(select Id_customer, sum(total_with_tax) total_with_tax from Sale group by Id_customer)
order by total_with_tax desc

How to create sql procedure for calculating Total dues

Can anyone help me by showing a create procedure statement for calculating Total Dues from three tables? Here are the tables along with their data ..
Table_1
accountno shipername shiperaddress Executivename
001 john 123, London Paul
002 Robi 127, China Soma
Table_2
Executivename shipername shiperaddress accountno currentamount anotheramount
paul john 123,london 001 10500 12000
soma robi 127,china 002 11000 6800
Table_3
accountno Date ReceivedAmount MoneyReceiptNo
001 1/1/2012 6500 G 256412
002 1/2/2012 5200 D 246521
Here I am to mention that the Total Dues will be calculated as
(currentamount + anotheramount) - receivedamount
I tried to do that by the following stored procedure.
CREATE PROCEDURE [dbo].[rptexetotaldues] #Executivename varchar(20)
AS BEGIN
select
table_1.Executivename,
sum(table_2.currentamount + table_2.anotheramount
- table_3.receivedamount ) as TotalDues
from
table_1
full join
table_2 on table_1.accountno = table_2.accountno
join
table_3 on table_3.accountno = table_1.accountno
where
table_1.Executivename = #Executivename
group by
table_1.Executivename
end
But that doesn't work. Please somebody help me.
Your sample worked for me. The only thing I changed is "Date" to transdate. I strongly recommend avoiding "Date" as a column name. I also changed the aliasing a bit, but that should have been allright. I thinkg #Gordon Linoff is right - you could have an issue with NULLS.
DECLARE #table_1 TABLE (accountno char(5), shipername char(20), shiperaddress char(40), Executivename varchar(20))
INSERT INTO #table_1 VALUES ('001', 'john', '123, London', 'Paul')
INSERT INTO #table_1 VALUES ('002','Robi','127, China','Soma')
DECLARE #table_2 TABLE (Executivename varchar(20), shipername char(20), shiperaddress char(40),
accountno char(20), currentamount decimal(10,2), anotheramount decimal(10,2))
INSERT INTO #table_2 VALUES ('paul', 'john','123,london','001',10500, 12000)
INSERT INTO #table_2 VALUES ('soma', 'robi', '127,china', '002', 11000, 6800)
DECLARE #table_3 TABLE(accountno char(20), tranDate datetime, ReceivedAmount decimal(10,2), MoneyReceiptNo char(10))
INSERT INTO #table_3 VALUES ('001', '1/1/2012', 6500, 'G 256412')
INSERT INTO #table_3 VALUES ('002', '1/2/2012', 5200,'D 246521')
DECLARE #Executivename varchar(20)
--SET #Executivename = 'Paul'
SET #Executivename = 'Soma'
select
tb1.Executivename,
sum(tb2.currentamount + tb2.anotheramount - tb3.receivedamount ) as TotalDues
from
#table_1 tb1
full join #table_2 tb2 on tb1.accountno = tb2.accountno
join #table_3 tb3 on tb3.accountno = tb1.accountno
where
tb1.Executivename=#Executivename group by tb1.Executivename
Here are my results:
Executivename TotalDues
Soma 12600.00
I can think of two problems. First is that the account number is duplicated in either table 1 or table 2. This will add extra rows.
The second is that there are rows in table three that are not in table 2. This means that the addition within the sum is NULL because one of the values is NULL. You can fix this in one of these ways:
sum(table_2.currentamount) + sum(table_2.anotheramount) - sum(table_3.receivedamount)
or
sum(coalesce(table_2.currentamount, 0.0) + coalesce(table_2.anotheramount, 0.0) - coalesce(table_3.receivedamount, 0.0) ) as TotalDues
I think it would be more straightforward as a UNION query, example below:
CREATE PROCEDURE [dbo].[rptexetotaldues] #Executivename varchar(20)
AS BEGIN
SELECT SUB.ACCOUNTNO, SUM(SUB.DUE) AS TOTALDUE FROM
(SELECT ACCOUNTNO
, CURRENTAMOUNT AS DUE
FROM TABLE_2
INNER JOIN TABLE_1 -- WILL ONLY WORK IF ACCOUNTNO IS UNIQUE WITHIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE2.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
UNION ALL
SELECT ACCOUNTNO
, ANOTHERAMOUNT AS DUE
FROM TABLE_2
INNER JOIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE2.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
UNION ALL
SELECT ACCOUNTNO
, -RECEIVEDAMOUNT AS DUE -- NOTE NEGATIVE SIGN
FROM TABLE 3
INNER JOIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE3.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
) SUB
GROUP BY SUB.ACC