SQLite conditional SELECT statement - multiple criteria but single statement - sql

I have 2 tables, one is a list of customers, the other a list of historic and future delivery dates for these customers.
Convenience code to create example table:
CREATE TABLE Customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);
INSERT INTO Customers (name) VALUES ('David');
INSERT INTO Customers (name) VALUES ('John');
INSERT INTO Customers (name) VALUES ('Anne');
CREATE TABLE Orders (
id INTEGER,
item TEXT,
delivery_date TEXT
);
INSERT INTO Orders VALUES ( 1, 'gopro' , '2016-04-05');
INSERT INTO Orders VALUES ( 1,'car', '2015-12-30');
INSERT INTO Orders VALUES ( 1,'watch', '2015-10-20');
INSERT INTO Orders VALUES ( 2, 'laptop', '2016-04-15');
INSERT INTO Orders VALUES ( 3, 'car', '2016-01-15');
INSERT INTO Orders VALUES ( 3,'cup', '2015-11-30');
I need to create a SQL statement that shows all customers and their most recent and next delivery date.
(Something like - SELECT * from Customers with recent and next item and date FROM Orders.)
Expected Result Table
Name, Most Recent Item, Recent Date, Next Item, Next Date
David, car, 2015-12-30, gopro, 2016-04-05
John, NULL, NULL, laptop, 2016-04-15
Anne, car, 2016-01-15, NULL, NULL
But the closest I can get with a single statement is:
SELECT
(SELECT o.item from Orders WHERE delivery_date < date('now') ORDER BY delivery_date DESC LIMIT 1) as Last_Item_Ordered,
(SELECT o.delivery_date from Orders WHERE delivery_date < date('now') ORDER BY delivery_date DESC LIMIT 1) as Last_Delivery_Date,
(SELECT o.item from Orders WHERE delivery_date >= date('now') ORDER BY delivery_date ASC LIMIT 1) as Next_Item_Ordered,
(SELECT o.delivery_date from Orders WHERE delivery_date >= date('now') ORDER BY delivery_date ASC LIMIT 1) as Next_Delivery_Date,
c.*
FROM (Orders o INNER JOIN Customers c ON c.id = o.id)
GROUP BY c.name
ORDER BY c.id;
and the Actual results are as this:
Last_Item_Ordered Last_Delivery_Date Next_Item_Ordered Next_Delivery_Date id name
watch 2015-10-20 watch 2015-10-20 1 David
laptop 2016-04-15 laptop 2016-04-15 2 John
cup 2015-11-30 cup 2015-11-30 3 Anne
Todays date is 21st February 2016, hence some values are expected to be NULL for the above customers future results.
If anyone can help, be greatly appreciated. thanks

You can use the following query:
SELECT (SELECT o.item
from Orders AS o
WHERE o.id = c.id AND delivery_date < date('now')
ORDER BY delivery_date DESC LIMIT 1) as Last_Item_Ordered,
(SELECT o.delivery_date
from Orders AS o
WHERE o.id = c.id AND delivery_date < date('now')
ORDER BY delivery_date DESC LIMIT 1) as Last_Delivery_Date,
(SELECT o.item
from Orders AS o
WHERE o.id = c.id AND delivery_date >= date('now')
ORDER BY delivery_date ASC LIMIT 1) as Next_Item_Ordered,
(SELECT o.delivery_date
from Orders AS o
WHERE o.id = c.id AND delivery_date >= date('now')
ORDER BY delivery_date ASC LIMIT 1) as Next_Delivery_Date,
c.*
FROM Customers c
ORDER BY c.id;
Demo here

Related

How ovoid duplicate code in sql query subQuery

I'm new in SQL. Need some help to improve my query to ovoid duplicate code.
SELECT customers.name, orders.price
FROM customers
JOIN orders ON orders.id = customers.order_id
WHERE customers.order_id IN (
SELECT orders.id
FROM orders
WHERE orders.price = (
SELECT orders.price
FROM orders
WHERE orders.order_date BETWEEN
(SELECT MIN(orders.order_date) FROM orders)
AND
(SELECT DATE_ADD(MIN(orders.order_date), INTERVAL 10 year)FROM orders)
ORDER BY orders.price DESC LIMIT 1
)
AND orders.order_date BETWEEN
(SELECT MIN(orders.order_date) FROM orders)
AND
(SELECT DATE_ADD(MIN(orders.order_date), INTERVAL 10 year)FROM orders)
)
I would like ovoid duplicate code here
SELECT MIN(orders.order_date) FROM orders
and
SELECT DATE_ADD(MIN(orders.order_date), INTERVAL 10 year)FROM orders
You can use WITH to get first 10 years orders. By defitinion there exists no orders with the date < min(date), so you needn't between, just <= .
firstOrders as (
SELECT *
FROM orders
WHERE order_date <=
(SELECT DATE_ADD(MIN(o.order_date), INTERVAL 10 year)
FROM orders o)
)
SELECT customers.name, orders.price
FROM customers
JOIN FirsrOrders orders ON orders.id = customers.order_id
AND orders.price = (
select price
from firstOrders
order py price desc
limit 1
)
You want orders from the first ten years where the price was equal to the maximum price among those orders. So rank by price and grab those holding the #1 spot.
with data as (
select *,
date_add(min(order_date) over (), interval 10 year) as max_date,
rank() over (order by price desc) as price_rank
from orders
)
select *
from data
where order_date <= max_date and price_rank = 1;

On same row: last purchase quantity + date, and total quantity in stock (several stock places) - SQL server

I am trying to get the following result in SQL server:
From the purchase order rows, last purchase quantity + date from all item codes in the order rows table and from the warehouse table amount in stock for the item codes I get from the rows table.
Order rows:
ORDER_DATE ITEM_CODE QTY
2019-03-01 A 5
2019-03-02 A 3
2019-03-05 A 4
2019-03-03 B 3
2019-03-04 B 10
Warehouse:
ITEM_CODE INSTOCK STOCKPLACE
A 10 VV
A 3 LP
A 8 XV
B 5 VV
B 15 LP
Wanted result (Latest order date, latest order qty and total in stock):
ORDER_DATE ITEM_CODE QTY INSTOCK
2019-03-05 A 4 21
2019-03-04 B 10 20
I have tried some queries but only failed. I have a steep learning curve ahead of me :) Thanks in advance for all the help!
Here is one method:
select o.*, wh.*
from (select wh.item_code, sum(wh.instock) as instock
from warehouse wh
group by wh.item_code
) wh outer apply
(select top (1) o.*
from orders o
where o.item_code = wh.item_code
order by o.order_date desc
) o;
You can use row_number() with apply :
select t.*, wh.instock
from (select o.*, row_number () over (partition by item_code order by o.order_date desc) as seq
from Order o
) t cross apply
( select sum(wh.instock) as instock
from warehouse wh
where wh.item_code = t.item_code
) wh
where t.seq = 1;
Your Orders aren't identified with a unique ID, and therefore if multiple Orders were to coincide on the same date, you have no way of telling which is the most recent order on that day.
Anyway, assuming that the database you posted is correct and an Order date + Item Code combines to form a unique key, you could use grouping and some CTE to get the desired output as follows.
;WITH MostRecentOrders (ITEM_CODE, ORDER_DATE)
AS (
SELECT
O.ITEM_CODE
, MAX(O.ORDER_DATE) AS ORDER_DATE
FROM
#Order O
GROUP BY ITEM_CODE
)
SELECT
O.ORDER_DATE
, O.ITEM_CODE
, O.QTY
, SUM(WH.INSTOCK) AS INSTOCK
FROM
#Warehouse WH
INNER JOIN #Order O ON O.ITEM_CODE = WH.ITEM_CODE
INNER JOIN MostRecentOrders MRO ON MRO.ITEM_CODE = O.ITEM_CODE
AND MRO.ORDER_DATE = O.ORDER_DATE
GROUP BY
O.ORDER_DATE
, O.ITEM_CODE
, O.QTY
ORDER BY O.ITEM_CODE

SQL complex select

I have 2 SQL tables.
for Books:
create table product
(
product_id number primary key
name varchar2(128 byte) not null,
rrp number not null,
available_from date not null
);
and for Orders:
create table orders
(
order_id number primary key,
product_id number not null,
quantity number not null,
order_price number not null,
dispatch_date date not null,
foreign key (product_id) references product(product_id)
);
How to write a query to find books that have sold fewer than 10 copies in the last year, excluding books that have been available for less than 1 month?
I expect this would be smth like:
SELECT name FROM products WHERE
today - products.available_from >= 30
AND
10 > (SELECT COUNT(product_id) FROM orders WHERE orders.product_id = products.product_id AND today - products.dispatch_date <= 365)
On SQL Server this will be something like...............
Select B.ProductId, B.Name, SUM(O.quantity) as OrderedAmount
FROM Books B
INNER JOIN Orders O ON O.product_id = B.ProductId
WHERE
B.available_from <= DateAdd( month, -1, GETDATE()) --Exclude 1 month books
AND O.OrderDate BETWEEN DateAdd( year, -1, GETDATE()) AND GETDATE() --Ordered in the last year
GROUP BY
B.ProductId, B.Name
HAVING SUM(O.quantity) < 10 --Sum of quantity ordered less than 10
On Oracle:
SELECT p.name
FROM product p
LEFT JOIN orders o ON p.product_id=o.product_id -- makes sure books with no orders are also included
WHERE
(p.available_from < add_months(sysdate,-1) -- available for 1 month or more
AND
(o.DISPATCH_DATE IS NULL -- books with no rows in "orders"
OR
p.PRODUCT_ID IN -- books that have sold fewer than 10 copies in last year
(SELECT product_id
FROM ORDERS
WHERE dispatch_date > add_months(sysdate,-12)
GROUP BY product_id
HAVING SUM(quantity) < 10)
)
);

How to get the discount number of customers in prior period?

I have a requirement where I supposed to roll customer data in the prior period of 365 days.
Table:
CREATE TABLE orders (
persistent_key_str character varying,
ord_id character varying(50),
ord_submitted_date date,
item_sku_id character varying(50),
item_extended_actual_price_amt numeric(18,2)
);
Sample data:
INSERT INTO orders VALUES
('01120736182','ORD6266073' ,'2010-12-08','100856-01',39.90),
('01120736182','ORD33997609' ,'2011-11-23','100265-01',49.99),
('01120736182','ORD33997609' ,'2011-11-23','200020-01',29.99),
('01120736182','ORD33997609' ,'2011-11-23','100817-01',44.99),
('01120736182','ORD89267964' ,'2012-12-05','200251-01',79.99),
('01120736182','ORD89267964' ,'2012-12-05','200269-01',59.99),
('01011679971','ORD89332495' ,'2012-12-05','200102-01',169.99),
('01120736182','ORD89267964' ,'2012-12-05','100907-01',89.99),
('01120736182','ORD89267964' ,'2012-12-05','200840-01',129.99),
('01120736182','ORD125155068','2013-07-27','201443-01',199.99),
('01120736182','ORD167230815','2014-06-05','200141-01',59.99),
('01011679971','ORD174927624','2014-08-16','201395-01',89.99),
('01000217334','ORD92524479' ,'2012-12-20','200021-01',29.99),
('01000217334','ORD95698491' ,'2013-01-08','200021-01',19.99),
('01000217334','ORD90683621' ,'2012-12-12','200021-01',29.990),
('01000217334','ORD92524479' ,'2012-12-20','200560-01',29.99),
('01000217334','ORD145035525','2013-12-09','200972-01',49.99),
('01000217334','ORD145035525','2013-12-09','100436-01',39.99),
('01000217334','ORD90683374' ,'2012-12-12','200284-01',39.99),
('01000217334','ORD139437285','2013-11-07','201794-01',134.99),
('01000827006','W02238550001','2010-06-11','HL 101077',349.000),
('01000827006','W01738200001','2009-12-10','EL 100310 BLK',119.96),
('01000954259','P00444170001','2009-12-03','PC 100455 BRN',389.99),
('01002319116','W02242430001','2010-06-12','TR 100966',35.99),
('01002319116','W02242430002','2010-06-12','EL 100985',99.99),
('01002319116','P00532470001','2010-05-04','HO 100482',49.99);
Using the query below I am trying to get the number of distinct customers by order_submitted_date:
select
g.order_date as "Ordered",
count(distinct o.persistent_key_str) as "customers"
from
generate_series(
(select min(ord_submitted_date) from orders),
(select max(ord_submitted_date) from orders),
'1 day'
) g (order_date)
left join
orders o on o.ord_submitted_date between g.order_date - interval '364 days'
and g.order_date
WHERE extract(year from ord_submitted_date) <= 2009
group by 1
order by 1
This is the output I expected.
Ordered Customers
2009-12-03 1
2009-12-10 1
When I execute the query above I get incorrect results.
How can I make this right?
To get your expected output ("the number of distinct customers") - only days with actual orders 2009:
SELECT ord_submitted_date, count(DISTINCT persistent_key_str) AS customers
FROM orders
WHERE ord_submitted_date >= '2009-1-1'
AND ord_submitted_date < '2010-1-1'
GROUP BY 1
ORDER BY 1;
Formulate the WHERE conditions this way to make the query sargable, and input easy.
If you want one row per day (from the earliest entry up to the latest in orders) - within 2009:
SELECT ord_submitted_date AS ordered
, count(DISTINCT o.persistent_key_str) AS customers
FROM (SELECT generate_series(min(ord_submitted_date) -- single query ...
, max(ord_submitted_date) -- ... to get min / max
, '1d')::date FROM orders) g (ord_submitted_date)
LEFT join orders o USING (ord_submitted_date)
WHERE ord_submitted_date >= '2009-1-1'
AND ord_submitted_date < '2010-1-1'
GROUP BY 1
ORDER BY 1;
SQL Fiddle.
Distinct customers per year
SELECT extract(year from ord_submitted_date) AS year
, count(DISTINCT persistent_key_str) AS customers
FROM orders
GROUP BY 1
ORDER BY 1;
SQL Fiddle.

How to identify to correct row

I have two tables, namely Price List (Table A) and Order Record (Table B)
Table A
SKU Offer Date Amt
AAA 20120115 22
AAA 20120223 24
AAA 20120331 25
AAA 20120520 28
Table B
Customer SKU Order Date
A001 AAA 20120201
B001 AAA 20120410
C001 AAA 20120531
I have to retrieve the correct pricing for each customer based on the order date. The expected output should be like this:-
Customer SKU Order Date Amt
A001 AAA 20120201 22
B001 AAA 20120410 25
C001 AAA 20120531 28
Thanks.
A left join (or NOT EXISTS subquery) can be used to ensure that the join between the two tables uses the "most recent" row from the prices table that is dated on or before the order date. I assume that's the relationship between the tables that you want to achieve:
Setup:
create table Prices (
SKU char(3) not null,
OfferDate date not null,
Amt int not null
)
go
insert into Prices (SKU, OfferDate, Amt) values
('AAA','20120115', 22),
('AAA','20120223', 24),
('AAA','20120331', 25),
('AAA','20120520', 28)
go
create table Orders (
Customer char(4) not null,
SKU char(3) not null,
OrderDate date not null
)
go
insert into Orders (Customer, SKU, OrderDate) values
('A001','AAA','20120201'),
('B001','AAA','20120410'),
('C001','AAA','20120531')
go
Query:
select
o.*, /* TODO - Explicit columns */
p.Amt
from
Orders o
inner join
Prices p
on
o.SKU = p.SKU and
o.OrderDate >= p.OfferDate
left join
Prices p_later
on
o.SKU = p_later.SKU and
o.OrderDate >= p_later.OfferDate and
p_later.OfferDate > p.OfferDate
where
p_later.SKU is null
Next time, do put up what u have tried....
anyways, here is your answer! try...
Select X.Customer , X.SKU , X.OrderDate , Y.Amt from B as X INNER JOIN A as Y ON X.Order Date= Y. Offer Date
good luck...
SELECT o.Customer, o.SKU, o.[Order Date],
(SELECT TOP 1 l.Amt
FROM PriceList l
WHERE l.[Offer Date] <= o.[Order Date] AND o.SKU = l.SKU
ORDER BY l.[Offer Date] DESC) AS Amount
FROM
Orders o
Some things may differ based on database support