I'm facing the following problem, I'm still fairly new to rails and I need your help
I have a table SALES with 4 columns: product_id, quantity of the product sold, the seller and the day of the selling.
I have other table PRODUCT_PRICE with the list of the products, the price and the month (price changes based on month)
Finally I have other table PRODUCT where I have the product, description, and manufactor_id of the product.
I need to make 2 queries:
- the top 10 manufactors with more products sold in the last month
- the top 10 sellers with more revenue (using the PRODUCT_PRICE table to calculate) in the last month.
How can I do this with ActiveRecord in Ruby on Rails, I would like to use rails associations to do this.
Thanks!
Not tested and quite difficult without any further information, but if you have the three models setup:
For the first, based on this query:
SELECT manufacturer_id FROM products
LEFT JOIN sales ON sales.product_id = products.id
WHERE YEAR(sales.created_at) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(sales.created_at) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
LIMIT 10
It would be something like this (you don't mention which version of Rails you are using)
#top_manufacturers = Product.find(:all,
:select=> 'manufacturer_id FROM products',
:joins => 'LEFT JOIN sales ON sales.product_id = products.id',
:conditions => 'YEAR(created_at) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH) AND MONTH(created_at) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)',
:limit => 10)
For the second
SELECT sales.seller_id, SUM(sales.quantity), SUM(product_prices.price) FROM sales
LEFT JOIN products ON products.id = sales.product_id
LEFT JOIN product_prices ON product_prices.product_id = products.id
WHERE YEAR(sales.created_at) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(sales.created_at) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
LIMIT 10
#top_sellers = Sale.find(:all,
:select => 'sales.seller_id, SUM(sales.quantity), SUM(product_prices.price)',
:joins => 'LEFT JOIN products ON products.id = sales.product_id LEFT JOIN product_prices ON product_prices.product_id = products.id',
:conditions => 'YEAR(sales.created_at) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH) AND MONTH(sales.created_at) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)',
:limit => 10)
If you don't have created_at and updated_at columns in all your tables then you should add them - Rails populates them automagically although I guess I should be using your month column.
Related
I have the following chunk of code, in which in trying to count the sales of beef, chicken and pork in each month of the last year (i also need to determine the market share of the meats each month)
SELECT
CAST(EXTRACT('MONTH' FROM TO_TIMESTAMP(FULLDATE, 'YYYY-MM-DD')) AS INT) AS month
FROM purchases_2020
JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
(
SELECT
COUNT (purchaseid) AS total_sales
FROM purchases_2020
JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
WHERE category = 'whole milk' OR category = 'yogurt' OR category = 'domestic eggs'
GROUP BY month
) a
GROUP BY month
ORDER BY month
The expected result is the following image
EDIT to add the exact error message
but in getting this error message
syntax error at or near "SELECT"
LINE 6: SELECT
^
[SQL: SELECT
CAST(EXTRACT('MONTH' FROM TO_TIMESTAMP(FULLDATE, 'YYYY-MM-DD')) AS INT) AS month
FROM purchases_2020
JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
(
SELECT
COUNT (purchaseid) AS total_sales
FROM purchases_2020
JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
WHERE category = 'whole milk' OR category = 'yogurt' OR category = 'domestic eggs'
GROUP BY month
) a
GROUP BY month
ORDER BY month
This is the data schema i'm working with.
EDIT
I'm aware i can query the total_sales like this:
SELECT
CAST(EXTRACT('MONTH' FROM TO_TIMESTAMP(FULLDATE, 'YYYY-MM-DD')) AS INT) AS month,
COUNT (purchaseid) AS total_sales
FROM purchases_2020
JOIN categories ON purchases_2020.purchaseid = categories.purchase_id
WHERE category = 'beef' OR category = 'pork' OR category = 'chicken'
GROUP BY month
ORDER BY month
But doing it like this locks me out of doing of writting the market_share formula on the select statement because of the WHERE statement no being inside a subquery.
This query should give you the count of sales by month and category. I can't test it because I don't have datas.
SELECT
c.category,
EXTRACT('MONTH' FROM FULLDATE) AS month,
count(purchaseid) AS total_sales
FROM purchases_2020 p JOIN categories c ON p.purchaseid = c.purchase_id
WHERE category in ('beef','pork','chicken')
GROUP BY month,c.category
ORDER BY month,c.category;
I have a DB with that tables.
Users (userId, age)
Purchases (purchaseId, userId, itemId, date)
Items (itemId, price).
I need to display the top 3 items by revenue (1 column), share in total revenue (2 column).
Example:
itemid share
1 20
2 10
3 8
Revenue = count purchased items * price.
My code
SELECT Items.itemid, SUM(Items.price) FROM Purchases
LEFT JOIN Items ON Items.itemid = Purchases.itemId
WHERE strftime('%Y', Purchases.date) = '2020'
GROUP BY Items.itemid
ORDER BY Items.itemid DESC LIMIT 3
I do not understand how to calculate the percentage of revenue in SQL and how to display it.
You can use window functions:
SELECT i.itemid, SUM(i.price),
SUM(i.price) * 1.0 / SUM(SUM(i.price)) OVER () as ratio
FROM Purchases p JOIN
Items i
ON i.itemid = p.itemId
WHERE p.date >= '2020-01-01' AND
p.date < '2021-01-01'
GROUP BY i.itemid
ORDER BY i.itemid DESC
LIMIT 3;
Note the changes to the query:
The use of table aliases, so the query is easier to write and to read.
The date filtering uses date constants, so the optimizer can use indexes/partitions if available.
Window functions provide the total that you want.
A LEFT JOIN is unnecessary. You need a match for items to have a total price.
There are 2 tables - Products and Sales
Products
prod_id
prod_nm
Sales
prod_id
cust_id
sls_dt
sls_amt
Write a query selecting ALL the products. For each product show total of sales amounts in the past 30 days or 0 if not sold in 30 day withoug using subqueries.
Since different RDBMS have different date functions, you can filter by date using the following pseudo code - sls_dt > now() - 30.
Im new to sql and im trying it like this as i found this online.
Select prod_id, prod_nm from(
Select sls_amt
From Sales) as t
Where t.rank = 1
However, this isnt' working. Any help is appreciated
Try below:
select p.prod_id,
p.prod_nm,
sum(s.sls_amt)
from products p
left outer join Sales s on p.prod_id = s.prod_id
and s.sls_dt > now() - 30
group by p.prod_id,
p.prod_nm;
Im trying to get sum of points for a user in the last month and the total, is it possible to get it in one query? Im using zend but i can probably get it working with provided sql.
heres my total for last month
$select = $this->_db
->select()
->from(array('p' => $this->_name), array(
'user_login',
'sum' => new Zend_Db_Expr('SUM(p.value)'),
)
)
->joinLeft(array('u' => 'user'), 'p.user_login = u.login')
->group('p.user_login')
->where('DATE(when) >= CURDATE() - INTERVAL 30 DAY')
->order('sum DESC')
;
return $this->getAdapter()->fetchAll($select);
As I understand the question, you want to show the total for the last 30 days and the total of all times for each user; sadly I can't test the Zend syntax and I'm not very used to it, but here is one version of the required SQL for MySQL;
SELECT p.user_login,
SUM(IF(DATE(`when`) >= CURDATE() - INTERVAL 30 DAY,p.value,0)) sum,
SUM(p.value) total_sum
FROM user_value p
JOIN user u
ON u.login = p.user_login
GROUP BY p.user_login
ORDER BY sum DESC;
SQLfiddle for testing.
I believe your initial query is equivalent to this SQL:
SELECT p.user_login, SUM(p.value) as sum_last_month
FROM person p
LEFT JOIN user u ON p.user_login = u.login
WHERE DATE(when) >= CURDATE() - INTERVAL 30 DAY
GROUP BY p.user_login
ORDER BY sum_last_month DESC
I'm not sure how to do a nested SELECT like this with Zend, but in SQL I believe something like this would work:
SELECT p.user_login, SUM(p.value) as sum_last_month,
(SELECT SUM(p2.value) FROM person p2 WHERE p2.id = p.id) as total
FROM person p
LEFT JOIN user u ON p.user_login = u.login
WHERE DATE(when) >= CURDATE() - INTERVAL 30 DAY
GROUP BY p.user_login
ORDER BY sum_last_month DESC, total DESC
I need to build a query with 4 columns (sql 2005).
Column1: Product
Column2: Units sold
Column3: Growth from previous month (in %)
Column4: Growth from same month last year (in %)
In my table the year and months have custom integer values. For example, the most current month is 146 - but also the table has a year (eg 2011) column and month (eg 7) column.
Is it possible to get this done in one query or do i need to start employing temp tables etc??
Appreciate any help.
thanks,
KS
KS,
To do this on the fly, you could use subqueries.
SELECT product, this_month.units_sold,
(this_month.sales-last_month.sales)*100/last_month.sales,
(this_month.sales-last_year.sales)*100/last_year.sales
FROM (SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 146 GROUP BY product) AS this_month,
(SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 145 GROUP BY product) AS last_month,
(SELECT product, SUM(units_sold) AS units_sold, SUM(sales) AS sales
FROM product WHERE month = 134 GROUP BY product) AS this_year
WHERE this_month.product = last_month.product
AND this_month.product = last_year.product
If there's a case where a product was sold in one month but not another month, you will have to do a left join and check for null values, especially if last_month.sales or last_year.sales is 0.
I hope I got them all:
SELECT
Current_Month.product_name, units_sold_current_month,
units_sold_last_month * 100 / units_sold_current_month prc_last_month,
units_sold_last_year * 100 / units_sold_current_month prc_last_year
FROM
(SELECT product_id, product_name, sum(units_sold) units_sold_current_month FROM MyTable WHERE YEAR = 2011 AND MONTH = 7) Current_Month
JOIN
(SELECT product_id, product_name, sum(units_sold) units_sold_last_month FROM MyTable WHERE YEAR = 2011 AND MONTH = 6) Last_Month
ON Current_Month.product_id = Last_Month.product_id
JOIN
(SELECT product_id, product_name, sum(units_sold) units_sold_last_year FROM MyTable WHERE YEAR = 2010 AND MONTH = 7) Last_Year
ON Current_Month.product_id = Last_Year.product_id
I am slightly guessing as the structure of the table provided is the result table, right? You will need to do self-join on month-to-previous-month basis:
SELECT <growth computation here>
FROM SALES s1 LEFT JOIN SALES s2 ON (s1.month = s2.month-1) -- last month join
LEFT JOIN SALES s3 ON (s1.month = s3.month - 12) -- lat year join
where <growth computation here> looks like
((s1.sales - s2.sales)/s2.sales * 100),
((s1.sales - s3.sales)/s3.sales * 100)
I use LEFT JOIN for months that have no previous months. Change your join conditions based on actual relations in month/year columns.