CREATE TABLE table1(
City CHAR(10),
Sales INT NOT NULL,
Sale_date DATE NOT NULL,
First_order INT NOT NULL
);
INSERT INTO table1 VALUES
("Paris",2000,'2018-01-02',1),
("Munich",2000,'2018-02-17',1),
("Paris",2000,'2018-03-31',2),
("Paris",1000,'2017-01-01',2),
("Paris",1000,'2017-02-02',1),
("Paris",1000,'2017-03-02',1),
("Paris",10000,'2018-01-02',2),
("Munich",1000,'2017-01-01',1);
http://sqlfiddle.com/#!9/f0f0cb/2
New to SQL, I'm getting an error from this query "Column 'City' in field list is ambiguous" is it a problem with the alias / inner join?
Objectives:
Daily Average sales per city (on q1 2018)
YoY sales growth Q1_2017 vs Q1_2018
Daily Average number of new customers (New customers have a value of 1 in the column "First_order" and 2 for returning customers)
On that 3rd point particularly I am lost, what should I use to calculate this? Count function?
When you have more than one table in a query, qualify all column references. That is, show the table where they come from.
So:
SELECT t1.City, AVG(t1.Sales) as q1_daily_avg_Sales,
(SUM(t1.Sales) - tt1.q1_2017_Sales) / tt1.q1_2017_Sales AS Sales_vs_SPLY
FROM table1 t1 INNER JOIN
(SELECT t1.City, SUM(t1.Sales) AS q1_2017_Sales
FROM table1 t1
WHERE t1.Sale_date BETWEEN '2017-01-01' AND '2017-03-31'
GROUP BY t1.City
) tt1
ON t1.City = tt1.City
WHERE t1.Sale_date BETWEEN '2018-01-01' AND '2018-03-31'
GROUP BY t1.City;
Here is the SQL Fiddle.
Related
the following table is supposed to reflect the storage location (stockId) of
purchases, where a purchase is received in parts at different times. (I omitted the date column.)
CREATE TABLE stock (purchaseNo INT NOT NULL, quantity INT NOT NULL, stockId INT NOT NULL)
Let's say purchase 10 has arrived in three parts and is stored at two different locations (5 and 6).
INSERT INTO stock VALUES(10, 2000, 5)
INSERT INTO stock VALUES(10, 3000, 5)
INSERT INTO stock VALUES(10, 1000, 6)
Now I would like to select those stocks having more than 2000 kg (quantity) available. This can be done with
SELECT stockId AS id, SUM(quantity) AS q
FROM stock
WHERE purchaseNo=10
GROUP BY stockId
HAVING q>2000
But since I am only interested in the stockId, I would like to prevent the quantity to be returned as well. Is this possible?
One of my failing attempts is
SELECT stockId AS id
FROM stock
WHERE purchaseNo=10 AND (SELECT SUM(quantity) FROM stock WHERE purchaseNo=10 AND stockId=id) >2000
with or without GROUP BY the following error is returned:
ERROR 1054 (42S22): Unknown column 'id' in 'where clause'
You could pass the SUM to HAVING and skip it from the results.
SELECT stockId AS id
FROM stock
WHERE purchaseNo=10
GROUP BY stockId
HAVING SUM(quantity)>2000;
SQLFiddle example.
Have you tried something like this?
SELECT distinct S1.stockId AS S1.id from stock S1
inner join(
SELECT S2.stockId AS S2.id, SUM(S2.quantity) AS S2.q
FROM stock S2
WHERE S2.purchaseNo=10
GROUP BY S2.stockId
HAVING S2.q>2000)
on S1.stockId=S2.stockId
I have these columns and data
Sample data:
CREATE TABLE Orders(customerid int, orderdate datetime, orderqty int);
INSERT into Orders(customerid, orderdate, orderqty) VALUES
(1,'2020-11-25',100),(1,'2020-11-27',160),(2,'2020-12-05',3490),
(1,'2020-11-29',293),(2,'2020-12-07',293),(1,'2020-12-01',382);
sqlfiddle: http://sqlfiddle.com/#!9/d90aaf/1/0
From this data, I want to find out the date difference in last 3 rows by each customer.
an example output would be:
customerid, last 3 orders average days between orders,sum of orderqty for last 3 order
1, 2,835
2, 2,3783
I have tried datediff() but I can't achieve this result by that function.
Can't figure out better trick for latest 3 orders. This works, but probably with not good performance with large tables:
SELECT o3.customerid,DATEDIFF(Latest1,IFNULL(Latest3,Latest2))/IF(Latest3 IS NULL,1,2) AS avgDiff,SUM(oQ.orderqty) AS qty3orders FROM
(SELECT o2.*,MAX(ooo.orderdate) AS Latest3 FROM
(SELECT o1.*,MAX(oo.orderdate) AS Latest2 FROM
(SELECT customerid,MAX(orderdate) AS Latest1 FROM Orders GROUP BY customerid) o1
JOIN Orders oo ON o1.customerid=oo.customerid AND oo.orderdate<o1.Latest1 GROUP BY o1.customerid) o2
LEFT JOIN Orders ooo ON o2.customerid=ooo.customerid AND ooo.orderdate<o2.Latest2 GROUP BY o2.customerid) o3
JOIN orders oQ ON o3.customerid=oQ.customerid AND oQ.orderdate>=COALESCE(o3.Latest3,o3.Latest2,o3.Latest1) GROUP BY o3.customerid
I want to join two tables. Tables are following below,
Table A:
Batch_ID INT,
Start_Dt DATE,
Expiry_Dt DATE
Table B:
Purchase_Dt DATE
I need to get two oldest batch code for each purchase date. Purchase date should be greater than or equal to start_dt and expiry_dt should be less than or equal to purchase date.
You can try using row_number()
select Purchase_Dt,Batch_ID from
(
select Purchase_Dt,Batch_ID,row_number() over(partition by Purchase_Dt order by batch_id desc) as rn
from B join A on Purchase_Dt>=start_dt and Purchase_Dt<=Expiry_Dt
)f where rn=1
Currently trying to create a query that shows how many accounts have paid month on month but on a cumulative basis (penetration). So as an example I have a table with Month paid and account number, which shows what month that account paid.
Month | AccountNo
Jan-14 | 123456
Feb-14 | 321654
So using the above the result set would show
Month | Payers
Jan-14 | 1
Feb-14 | 2
being because one account paid in Jan, then one in Feb meaning that there have been by the end of Feb 2 payments overall, but only one in Jan. Tried a few inner joins back onto the table itself with a t1.Month >= t2.Month as i would for a normal cumulative query but the result is always out.
Any questions please ask, unsure if the above will be clear to anyone but me.
If you have date in the table then you can try the following query.
SELECT [Month]
,(SELECT COUNT(AccountNo)
FROM theTable i
-- This is to make sure to add until the last day of the current month.
WHERE i.[Date] <= DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,o.[Date])+1,0)) AS CumulativeCount
FROM theTable o
Ok, several things. You need to have an actual date field, as you can't order by the month column you have.
You need to consider there may be gaps in the months - i.e. some months where there is no payment (not sure if that is true or not)
I'd recommend a recursive common table expression to do the actual aggregation
Heres how it works out:
-- setup
DECLARE #t TABLE ([Month] NCHAR(6), AccountNo INT)
INSERT #t ( [Month], AccountNo )
VALUES ( 'Jan-14',123456),('Feb-14',456789),('Apr-14',567890)
-- assume no payments in march
; WITH
t2 AS -- get a date column we can sort on
(
SELECT [Month],
CONVERT(DATETIME, '01 ' + REPLACE([Month], '-',' '), 6) AS MonthStart,
AccountNo
FROM #t
),
t3 AS -- group by to get the number of payments in each month
(
SELECT [Month], MonthStart, COUNT(1) AS PaymentCount FROM t2
GROUP BY t2.[Month], t2.MonthStart
),
t4 AS -- get a row number column to order by (accounting for gaps)
(
SELECT [Month], MonthStart, PaymentCount,
ROW_NUMBER() OVER (ORDER BY MonthStart) AS rn FROM t3
),
t5 AS -- recursive common table expression to aggregate subsequent rows
(
SELECT [Month], MonthStart, PaymentCount AS CumulativePaymentCount, rn
FROM t4 WHERE rn = 1
UNION ALL
SELECT t4.[Month], t4.MonthStart,
t4.PaymentCount + t5.CumulativePaymentCount AS CumulativePaymentCount, t4.rn
FROM t5 JOIN t4 ON t5.rn + 1 = t4.rn
)
SELECT [Month], CumulativePaymentCount FROM t5 -- select desired results
and the results...
Month CumulativePaymentCount
Jan-14 1
Feb-14 2
Apr-14 3
If your month column is date type then its easy to work on else you need some additional conversion for it. Here the query goes...
create table example (
MONTHS datetime,
AccountNo INT
)
GO
insert into example values ('01/Jan/2009',300345)
insert into example values ('01/Feb/2009',300346)
insert into example values ('01/Feb/2009',300347)
insert into example values ('01/Mar/2009',300348)
insert into example values ('01/Feb/2009',300349)
insert into example values ('01/Mar/2009',300350)
SELECT distinct datepart (m,months),
(SELECT count(accountno)
FROM example b
WHERE datepart (m,b.MONTHS) <= datepart (m,a.MONTHS)) AS Total FROM example a
I'm facing a mySQL problem :
I got a mySQL table wich contains these columns, it's store every orders and every state of the orders :
id_order_history / id_employee / id_order / id_order_state / date_add
I would like to get a list of *id_order* which are in a specific *id_order_state* - let's say 10 - but i don't want to get the orders where the state change after this particular state and don't want to collect the orders which are less than 7 day old ...
Here is how i tought to do this :
First a query to get a list of orders & date :
SELECT id_order, date
FROM '._DB_PREFIX_.'ps_order_history,
WHERE TO_DAYS(NOW()) - TO_DAYS(date_add) <= 7
AND id_order_state = 10
then a loop to get only the orders without newest state :
$query = ' SELECT id_order, date
FROM '._DB_PREFIX_.'ps_order_history,
WHERE ';
foreach ( $listAbove, $item) {
$query =+ '
(( date > $item['date'])
AND ( id_order = $item['id']))
';
}
$orderlist = Db::getInstance()->ExecuteS($query);
It's not really optimise, i pretty sure i can do it with only one query but don't really know how.
Do you have a clue to how make this cleaner ?
If I'm understanding this right, you only want the orders where the most recent state is equal to 10, for example. So lets start by getting the orders and the most recent state
SELECT
id_order,
MAX(id_order_history) as m
FROM ps_order_history
GROUP BY id_order
That gives us the latest order history item for each order (assuming id_order_history is the PK and that the largest value indicates the most recent order entry). Now we just search on that subquery to find the criteria we want.
SELECT
poh.id_order
FROM ps_order_history poh
INNER JOIN
(SELECT
id_order,
MAX(id_order_history) as m
FROM ps_order_history
GROUP BY id_order) sub
ON sub.id_order = poh.id_order
AND sub.m = poh.id_order_history
WHERE poh.id_order_state = 10
AND TO_DAYS(NOW()) - TO_DAYS(poh.date_add) <= 7
You can use a sub-query in the WHERE clause. Here's an example:
create table order_history
(orderid int, orderstate int, orderdate date,
primary key(orderid, orderstate, orderdate));
insert into order_history values (1,1,makedate(2012,1));
insert into order_history values (1,2,makedate(2012,2));
insert into order_history values (1,3,makedate(2012,3));
insert into order_history values (2,1,makedate(2012,1));
insert into order_history values (2,3,makedate(2012,3));
insert into order_history values (3,1,makedate(2012,1));
This query will now select all items whose latest orderstate is 3:
select a.orderid, a.orderdate from order_history a
where a.orderdate =
(select max(orderdate) from order_history b where b.orderid = a.orderid)
and a.orderstate=3
To restrict by orderdate, just add another clause for your date selection to the outer where clause.