Selecting lowest price for multiple products - sql

Hy all,
For a project i need an overview of all products to find the supplier with the lowest price. So for every product there must be 1 outcome with a price and supplier
If have tried like a hundred query but i just can't find the right one.
Tables:
CREATE TABLE [dbo].[product](
[id] [int] IDENTITY(1,1) NOT NULL,
[picture_name] [varchar](255) NOT NULL)
CREATE TABLE [dbo].[supplier](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL)
CREATE TABLE [dbo].[supplier_overview_product](
[supplier] [int] NOT NULL,
[product] [int] NOT NULL,
[price] [real] NOT NULL)
Product is FK to product
Supplier is FK to supplier
This is what i have:
SELECT s.name, MIN(sop.price)
FROM dbo.supplier_overview_product AS sop
JOIN dbo.product AS p
ON sop.product = p.id
JOIN dbo.supplier AS s
ON s.id = sop.supplier
GROUP BY s.name
But there is no supplier. And i want to know who that is.
Thanks in advance

I'm understanding your question to mean you want the supplier with the lowest price for each product.
The CTE orders the suppliers by price for each product, and the main query uses that ordering to only retrieve the supplier with the lowest price.
NOTE: Because I'm using RANK, if multiple suppliers happen to have the same lowest price, they will all be returned. If this is incorrect, change RANK to ROW_NUMBER
;WITH SuppliersByPrice AS (
SELECT product, supplier, price,
RANK() OVER (PARTITION BY product ORDER BY price) as ord
FROM supplier_overview_product
)
SELECT SBP.product, SBP.price, S.name
FROM SuppliersByPrice SBP
INNER JOIN Supplier S ON S.id = SBP.supplier
WHERE SBP.ord = 1

Related

Join 2 tables into 1

I have a Customer and Customer_2 table which I am trying to join together:
Both tables have data in them, but upon joining with a statement only the column names are being returned without data. I am trying to use the following join statement:
select distinct *
from Customer c
join Customer_2 d on c.CUST_NUM = d.CUST_NUM
These are the tables:
CREATE TABLE [Customer]
(
[CUST_NUM] [INT] NOT NULL,
[CUST_LNAME] [VARCHAR](50) NULL,
[CUST_FNAME] [VARCHAR](50) NULL,
CUST_BALANCE [MONEY] NOT NULL,
)
ON [PRIMARY]
CREATE TABLE [Customer_2]
(
[CUST_NUM] [INT] NOT NULL,
[CUST_LNAME] [VARCHAR](50) NULL,
[CUST_FNAME] [VARCHAR](50) NULL,
)
ON [PRIMARY]
Data in each Table:
INSERT INTO Customer
VALUES
('1000', 'Smith', 'Jeanne', '1050.11'),
('1001', 'Ortega', 'Juan', '840.92');
INSERT INTO CUSTOMER_2
VALUES
('2000', 'McPherson', 'Anne'),
('2001', 'Ortega', 'Juan'),
('2002', 'Kowalski', 'Jan'),
('2003', 'Chan', 'George');
Expected output would be combining customer_2 onto the bottom of the customer table with the extra column CUST_BALANCE being 0 or null for each of the four customers on the customer 2 table. The desired output should also exclude the second entry for Juan Ortega or where CUSTOM_NUM is 2001
You can use UNION ALL for this operation. ie:
select cust_num, cust_fname, cust_lname, balance from Customer
union all
select cust_num, cust_fname, cust_lname, 0 from Customer_2 c2
where not exists (select * from Customer c
where c.cust_fname = c2.cust_fname and c.cust_lname = c2.cust_lname);
DBFiddle demo
PS: Probably it is not an official term but join, joins tables vertically while union [all] joins horizontally.
Another option
Just use an full outer join in the 2 tables.
You will get all the rows common and not common from both tables.
https://www.w3schools.com/sql/sql_join_full.asp

sqlite - join tables or subquery?

I have the following tables:
create table part_category(id text primary key);
create table parts (id text primary key not null,
cat references part_category(id));
create table products (id text primary key not null);
create table product_parts (product references products(id),
part references parts(id),
qty integer);
create table locations (id text primary key not null,
stage text not null);
create table stock (part references parts(id),
cat references part_category(id),
location references locations(id),
qty integer,
date text);
create table orders (part references parts(id),
cat references parts(cat),
product references products(id),
qty integer not null default 0,
date_order text,
date_due text,
date_done text,
status boolean,
primary key(part, product, date_due));
And I'd like to have this returned from a select:
Part, Category, Product, Qty, Date Ordered, Date Due, qty of material, qty of stock, qty of wip
The columns bolded above are the ones that I can't figure out. Below is my select with the subquery where I'm trying to get the qty of stock.
The problem is the query is returning zero for everything.
orders = db.execute('''select distinct o.part, o.cat, o.product, o.qty,
o.date_order, o.date_due, o.date_done,
julianday(date_due) - julianday(date_order) as days_due,
(select stock.qty from stock, orders
where stock.part = orders.part and stock.location = 'stock' and orders.status = 1)
as qty_stock
from orders as o join stock as s on o.part = s.part
where o.status = 1
order by o.date_due asc, o.product asc, o.part asc''').fetchall()
Example output is
for item in orders:
print item['part'], item['qty'], item['qty_stock']
SOME_PART_NUMBER 3 0
But should be:
SOME_PART_NUMBER 3 22
I'm unsure about your business logic.
I guess this is what you want.
select distinct o.part, o.cat, o.product, o.qty,
o.date_order, o.date_due, o.date_done,
julianday(date_due) - julianday(date_order) as days_due,
qs.stockQuantity as qty_stock
from orders as o
join stock as s on o.part = s.part
left join (select stock.part, sum(stock.qty) stockQuantity
from stock ss
join orders oo on ss.part = oo.part
where ss.location = 'stock' and oo.status = 1
group by stock.part
) qs on qs.part = o.part
where o.status = 1
order by o.date_due asc, o.product asc, o.part asc
The title says "join tables OR subquery". The sql does both. I'm not sayin' that's the problem. But it certainly adds a level of complexity that could be error prone. You could try removing the subquery and replace it with s.qty, then add s.location = "stock" to the WHERE clause.

NOT EXIST clause

I am trying to find Products that have never been ordered. My 2 tables look like this.
CREATE TABLE Orders
(OrderNum NUMBER(10) NOT NULL,
OrderDate DATE NOT NULL,
Cust NUMBER(10),
Rep NUMBER(10),
Mfr CHAR(3) NOT NULL,
Product CHAR(5) NOT NULL,
Qty NUMBER(5) NOT NULL,
Amount NUMBER(9,2) NOT NULL,
CONSTRAINT OrdersPK
PRIMARY KEY (OrderNum));
CREATE TABLE Products
(Mfr CHAR(3) NOT NULL,
Product CHAR(5) NOT NULL,
Description VARCHAR2(20) NOT NULL,
Price NUMBER(9,2) NOT NULL,
QtyOnHand NUMBER(5),
CONSTRAINT ProductsPK
PRIMARY KEY (Mfr, Product));
The code I currently have looks like this.
SELECT Mfr, Product
FROM Products
WHERE NOT EXISTS (SELECT Products.Mfr
FROM Orders, Products
WHERE Orders.Mfr = Products.Mfr);
Although I am not getting any errors there are also no results showing up.
**EDIT: There are 26 Products and 19 of them have been ordered. I am expecting to get 7 Results but I am getting 0.
You can use NOT EXISTS, but you need to compare both keys:
SELECT p.Mfr, p.Product
FROM Products p
WHERE NOT EXISTS (SELECT 1
FROM Orders o
WHERE o.Mfr = p.Mfr AND
o.Product = p.Product
);
This is a case where it makes lots of sense to have an auto generated primary key that can be used for foreign key relationships.
Try this one
SELECT Mfr, Product
FROM Products
WHERE NOT EXISTS (SELECT Orders.Mfr
FROM Orders
WHERE Orders.Mfr = Products.Mfr AND Orders.Product = Products.Product);
An alternative is to use the set operation operator EXCEPT - as you want "the set of Products that don't exist in Orders":
SELECT
Mfr,
Product
FROM
Products
EXCEPT
SELECT
DISTINCT
Mfr,
Product
FROM
Orders
You can then use this as a subquery to get full product information.
SELECT
*
FROM
Products
INNER JOIN (
SELECT
Mfr,
Product
FROM
Products
EXCEPT
SELECT
DISTINCT
Mfr,
Product
FROM
Orders
) AS ProductsWithNoOrders ON
Products.Mfr = ProductsWithNoOrders.Mfr AND
Products.Product = ProductsWithNoOrders.Product

SQL SELECT 2 table with include 2 columns

I want create a select in MSSQL (SSMS).
I have 2 tables :
Solds:
CREATE TABLE [dbo].[Solds](
[Short] [nchar](10) NOT NULL,
[Id_Sold] [int] NULL,
[Price] [float] NULL,
[Date] [date] NULL,
Fruits:
CREATE TABLE [dbo].[Fruits](
[Short] [nchar](10) NOT NULL,
[Name] [nchar](10) NULL,
And now I want to select ALL name of fruits and Price , include Fruits without price.
I wrote this :
SELECT Name.Fruits,Solds.Price FROM Solds
join
Fruits on Fruits.Short = Solds.Short
And this code show me only all Sold fruits,
The question is how can I add here the names of fruit that have not been sold?
I want output for example:
Carrot 1,20
Cucumber 2,80
Carrot 9,20
Orange NULL -- NULL or Blank
Just want to union Fruits that have not been sold.
Use LEFT JOIN:
SELECT f.Name,
COALESCE(s.Price, -1.0) AS Price
-- include the following if you want a label for sold/unsold
-- CASE WHEN s.Price IS NOT NULL THEN 'Sold' ELSE 'Not Sold' END AS status
FROM Fruits f
LEFT JOIN Solds s
ON f.Short = s.Short
Use LEFT OUTER JOIN:
SELECT f.Name,
isnull(s.Price, 0) AS Price
FROM Fruits f
LEFT OUTER JOIN Solds s
ON f.Short = s.Short
You can get more details about various joins from below mentioned link.
https://msdn.microsoft.com/en-us/library/zt8wzxy4.aspx

T-SQL - get count of joined entries

I wonder how better to write the following query to Microsoft SQL Server.
I have three tables: surveys, survey_presets and survey_scenes. They have the following columns:
CREATE TABLE [dbo].[surveys](
[id] [int] IDENTITY(1,1) NOT NULL,
[caption] [nvarchar](255) NOT NULL,
[creation_time] [datetime] NOT NULL,
)
CREATE TABLE [dbo].[survey_presets](
[id] [int] IDENTITY(1,1) NOT NULL,
[survey_id] [int] NOT NULL,
[preset_id] [int] NOT NULL,
)
CREATE TABLE [dbo].[survey_scenes](
[id] [int] IDENTITY(1,1) NOT NULL,
[survey_id] [int] NOT NULL,
[scene_id] [int] NOT NULL,
)
Both survey_presets and survey_scenes have foreign keys on surveys for survey_id column.
Now I want to select all surveys with the count of corresponding presets and scenes for each. Here is the "pseudo-query" of what I want:
SELECT
surveys.*,
COUNT(survey_presets, where survey_presets.survey_id = surveys.id),
COUNT(survey_scenes, where survey_scenes.survey_id = surveys.id)
FROM surveys
ORDER BY suverys.creation_time
I can do a mess with SELECT DISTINCT, JOIN, GROUP BY, etc., but I'm new to T-SQL and I doubt my query will be optimal in any sense.
I would do the counting in subqueries to avoid cartesian products. As you might have a few matching rows in presets and also a few in scenes resulting count might be multiplied. You might write simple join query and avoid the multiplication by counting distinct survey_presets.id and distinct survey_scenes.id though.
SELECT
surveys.*,
isnull(presets_count, 0) presets_count,
isnull(scenes_count, 0) scenes_count
FROM surveys
LEFT JOIN
(
SELECT survey_id,
count(*) presets_count
FROM survey_presets
GROUP BY survey_id
) presets
ON surveys.id = presets.survey_id
LEFT JOIN
(
SELECT survey_id,
count(*) scenes_count
FROM survey_scenes
GROUP BY survey_id
) scenes
ON surveys.id = scenes.survey_id
ORDER BY surveys.creation_time
How it works
You can introduce a special kind of subquery called derived table to FROM section of your query. Derived table is defined as normal query enclosed in parenthesis and followed by table alias. It cannot use any column from outer query, but can expose columns you use in ON section to join derived table to main body of the query.
In this case derived table simply count rows grouped by id; joins connect the counts to surveys.
SELECT surveys.ID, surveys.caption, surveys.creation_time,
count(survey_presets.survey_id) as survey_presets,
count(survey_scenes.survey_id) as survey_scenes
FROM surveys
LEFT OUTER JOIN survey_presets on survey_presets.survey_id = surveys.id
LEFT OUTER JOIN survey_scenes on survey_scenes.survey_id = surveys.id
GROUP BY surveys.ID, surveys.caption, surveys.creation_time
ORDER BY suverys.creation_time