SQL: Is it possible to merge these two SQL statements into a single query? - sql

I am using MS SQL Server 2014 on Windows 7.
In the database I have a table named Orders, which looks like this:
OrderID | CustomerID | OrderDate | ...
----------------------------------------
1028 90 2015-10-10
...
2416 68 2016-02-12
I needed two things:
the total number of customers
the number of customers this year.
I am a beginner in SQL, but I managed to write 2 SQL statements in my app that seem to do the job:
For requirement #1
SELECT COUNT(DISTINCT CustomerID) FROM Orders; // result = 74
For requirement #2:
SELECT COUNT(DISTINCT CustomerID) FROM Orders WHERE OrderDate >= '2016-01-01'; // result = 34
I would like to know if it's possible to merge/combine somehow the above 2 SQL statements into one single query...? Of course, I need both results: the total customers (74 in above case) and also the customers of this year (i.e. 34).
The database is a remote database, so any idea to speed-up the query performance is highly welcome :)

Use conditional aggregation:
SELECT COUNT(DISTINCT CustomerID) as Total,
COUNT(DISTINCT CASE WHEN OrderDate >= '2016-01-01' THEN CustomerID END) as Total_2016
FROM Orders;

You can combine the data horizontally as in the previous answer or you can combine them vertically using a UNION, like this, if you think you need a tabular form:
SELECT 'Total Customers' As Description, COUNT(DISTINCT CustomerID) As Number FROM Orders // total = 74
Union ALL
SELECT '2016 Customers' AS Description, COUNT(DISTINCT CustomerID) As Number FROM Orders WHERE OrderDate >= '2016-01-01'; // this_year = 34

Related

How to filter on a column in SQL?

The table has 3 fields and sample data.
customerid ordertype countoforders
1 APP 10
1 WEB 20
2 APP 10
3 WEB 10
4 APP 30
5 APP 40
5 WEB 10
I want to retrieve only APP order customers and it counts. How can I write the query for the same?
For example from above table APP only customers are 2 and 4.
Try this:
select customerid, countoforders from MY_TABLE
where ordertype = 'APP'
except
select customerid, countoforders from MY_TABLE
where ordertype <> 'APP'
You haven't specified what DBMS you're using, so I'll have to avoid making product specific recommendations.
If this is really urgent the UGLIEST way to achieve what you require would be to create a lookup table with all the 'WEB' orders you have in your table (customerid, ordertype) and perform a NOT EXISTS or NOT IN on that table (ex. SELECT customerid, ordertype, countoforders FROM TABLE_1 WHERE TABLE_1.customerid NOT IN (SELECT customerid FROM #lookup))
Performance-wise it may not be optimal but this would get the job done.

Must I use inner join if I want to use MAX() value as a "where" condition?

My table is like this:
ProductID ProductName SupplierID CategoryID Unit Price
1 Chais 1 1 10 boxes x 20 bags 18
2 Chang 1 1 24 - 12 oz bottles 19
3 Aniseed Syrup 1 2 12 - 550 ml bottles 10
4 Chef Anton's
Cajun Seasoning 2 2 48 - 6 oz jars 21.35
5 Chef Anton's
Gumbo Mix 2 2 36 boxes 25
I copy it from https://www.w3schools.com/sql/sql_func_max.asp
I tried the simple version of MAX() function test, it works. But when I use the HighestPrice in the WHERE condtion as following:
SELECT
MAX(Price) AS HighestPrice,
SupplierID
FROM Products
GROUP BY SupplierID
WHERE HighestPrice>20;
The sytem report ERROR as:
Error: misuse of aggregate: MAX()
Does it mean I must use inner join to get what I want?
Following query should work:
SELECT SupplierID, MAX(Price) AS HighestPrice
FROM Products
GROUP BY SupplierID
HAVING MAX(Price) > 20;
following is the correct syntax of writing any SQL query:
SELECT column_name1,
SUM(column_name2)
FROM table_name
WHERE [CONDITION]
GROUP BY column_name1
HAVING (arithematic function condition);
Use having instead of where .
Where is always used before group by statement. It is way to filter the data which is already available with us whereas having is used after group by statement because it is applied on the data which we are in process of making.
SELECT MAX(Price) AS HighestPrice, SupplierID
FROM Products
Group By SupplierID
having MAX(Price) > 20;
Let me know in case of any queries.
Just for fun. If you specifically want to use where condition for highest price instead of having clause as given by G.arima with max function again. Do this:-
SELECT *
FROM
(
SELECT
MAX(Price) AS HighestPrice,
SupplierID
FROM Products
GROUP BY SupplierID
) a
WHERE HighestPrice>20;
Hope it helps :-)
By way of explanation of G.arima’s answer above:
When you use GROUP BY, you effectively create a new virtual table which contains only the GROUP BY fields as well as summaries.
There are two filter clauses, WHERE and HAVING, but they have a distinct role.
WHERE filters the original table. This gives you the formula FROM … WHERE …
HAVING filters the groups. This gives you the formula GROUP BY … HAVING …
What you ask is OK, but the clause is the wrong one. As G.arima says, you should use HAVING.

Aggregate function in inline view

I am trying to write some SQL for Pervasive database but I can't get my query working.
let me present a simple example. Imagine I have the following table:
PURCHASES:
OrderNumber CustomerName
55 Amy
56 Dan
57 Bob
58 Dan
59 Dan
60 Bob
61 Amy
62 Cindy
63 Dan
now I can use the query select count(OrderNumber) as "Number of orders palced", CustomerName from PURCHASES group by CustomerName order by count(OrderNumber) desc to get this result for the inline view:
Number of orders placed CustomerName
4 Dan
2 Amy
2 Bob
1 Cindy
But I don't want to stop here I want to know how many customers exist for each "Number of orders placed" but I can't get this query right.
I want to use this as a subquery something like this:
select x."Number of orders placed",count(x.CustomerName) as
"Number of customers that have purchased this many orders" from
(
select count(OrderNumber) as "Number of orders placed", CustomerName from PURCHASES
group by CustomerName
) x
group by x."Number of orders placed"
my query is failing miserably I think because column labels is not the proper way to refer to the the subquery.
The result I want to get should look like this:
Number of orders placed Number of customers...
4 1
2 2
1 1
help and explanation is appreciated
I see nothing wrong in your query except for order by in the inline view.
select x."Number of orders placed",count(x.CustomerName) as
"Number of customers that have purchased this many orders"
from
(select count(OrderNumber) as "Number of orders placed", CustomerName
from PURCHASES
group by CustomerName
) x
group by x."Number of orders placed"

Postgresql : Check if the last number is the highest

I have large database and one field should be an incremental number, but it sometimes resets and I must detect them (the bold rows)
Table 1:
Shop #Sell DATE
EC1 56 1/10/2015
EC1 57 2/10/2015
**EC1 11 3/10/2015
EC1 12 4/10/2015**
AS2 20 1/10/2015
AS2 21 2/10/2015
AS2 22 3/10/2015
AS2 23 4/10/2015
To solve this problem I thought to find the highest number of each SHOP and check if it is the number with the highest DATE. Do you know another easier way to do it?
My concern is that it can be a problem to do the way I am thinking since I have a large database.
Do you know how I can do the query I am thinking of or do you have any others ideas?
The query you have in mind will give you all Shop values having a discontinuity in Sell number.
If you want to get the offending record you can use the following query:
SELECT Shop, Sell, DATE
FROM (
SELECT Shop, Sell, DATE,
LAG(Sell) OVER (PARTITION BY Shop ORDER BY DATE) AS prevSell
FROM Shops ) t
WHERE Sell < prevSell
ORDER BY DATE
LIMIT 1
The above query will return the first discontinuity found within each Shop partition.
Output:
Shop Sell DATE
---------------------
EC1 11 2015-03-10
Demo here
EDIT:
In case you cannot use windowed function and you only want the id of the shop having the discontinuity, then you can use the following query:
SELECT s.Shop
FROM Shops AS s
INNER JOIN (
SELECT Shop, MAX(Sell) AS Sell, MAX(DATE) AS DATE
FROM Shops
GROUP BY Shop ) t
ON s.Shop = t.Shop AND s.DATE = t.DATE
WHERE t.Sell <> s.Sell
The above will work provided that you have unique DATE values per Shop.
I think the following is the type of query you want:
select s.*
from (select shop, max(sell) as maxsell,
first_value(sell) over (partition by shop order by date desc) as lastsell
from shops s
group by shop
) s
where maxsell <> lastsell;

Sql query to calculate first occurrence of a sales order not fulfilled by stock

I have two tables:
Sales Orders (SO ) with fields:Part, Due_Date, Qty
Part with fields Part and Stock.
I an trying to write a query that will produce the first occurrence ( by date - SO.Due_Date) that a sales order (SO.Qty) cannot be fulfilled by the stock.
This is easy if there is no stock i.e. Part.Stock=0 or if there is only one sales order for the part (SO.Qty > Part.Stock)
If there are multiple sales orders I only want the first one shown e.g.
Part.Part = Box , Part.Stock = 250
SO.Part | SO.Due_Date | SO.Qty
Box | 26/10/2014 | 100
Box | 27/10/2014 | 100
Box | 28/10/2014 | 100 * Return this row
Box | 29/10/2014 | 100
I think I need a sub query or need to use CTE but I can't work it out unless I use a loop. The tables have thousands of parts and sales orders and I am trying to run this query as quickly as possible.
Many thanks for your help
I assume this is a learning exercise, as no real business would work this way.
Anyway, here is a query to do what you want:
select *
from sales_order as so1
where due_date =
(select min(due_date)
from sales_order as so2
inner join part as p on p.part = so2.part
where so1.part = so2.part
and stock < (
select sum(quantity)
from sales_order as so3
where so3.due_date <= so2.due_date
and so3.part = so2.part
)
)
Which I have put into a working fiddle here: http://sqlfiddle.com/#!2/bd8ab5/1
There are some assumptions such as one order per date, but I believe it answers the question.
A query that uses a self join to calculate the running quantity total for each row and selects the row with the smallest due date having a running total greater than p.stock
select so.part, so.due_date, so.quantity
from sales_order so
join part p on p.part = so.part
join sales_order so2 on so2.part = so.part
and so2.due_date <= so.due_date
where p.part = 'Box'
group by so.part, so.due_date, so.quantity
having sum(so2.quantity) > max(p.stock)
order by so.due_date limit 1