SQL query with SUM and DATE_FORMAT - mysql

I hope for your help
I have three tables with relation, activity [id, amount, completed], brand_to_activity [id, activity_id, brand_id], brand [id, name] Need to get the top 3 brands selling by the sum grouped by month, for example, in January, the amount is 100 [this is the sum of the three best selling brands in January], the completed column in unixtime therefore you have to use DATE_FORMAT, i have now the following:
SELECT `activity`.*, SUM(activity.amount) as groupAmount,
DATE_FORMAT(FROM_UNIXTIME(activity.completed), '%m-%Y') as grouping
FROM `activity`
LEFT JOIN `brand_to_activity` ON `activity`.`id` = `brand_to_activity`.`activity_id`
WHERE (`activity`.`completed` BETWEEN '1546300800' AND '1577750400')
GROUP BY `grouping` ORDER BY `activity`.`completed`
Must be something like this:
Grouping | Amount | Profit | Note
January 100 50 Philips, Sony, Apple
February 100 50 Apple, Microsoft, Canon
March 50 50 Philips, Apple, AOC
version MariaDB 10
https://mega.nz/#!zFdAHACA!2CCVBVjMvwAxMqEz202a107s1CDxKc8jkvZiGQ5NJ0c
https://mega.nz/#!jNFCCQiL!MODxZR5kwCBXG6789uBZEVZhsdcZxY8W55qyIa-B4KQ
https://mega.nz/#!XRcAWAIT!xASyVxE3ucRiVtLJmjCKys7plImxLMOH99dRQVVSkDM

Related

How do I sum a column, and join it to another table based on a condition in SQL?

I have two tables in SQL, one that contains product_id, products_name, department_name, and product_sales and one that has department_id, department_name, and over_head_costs.
I want to be able to find the sum of all sales (grouped by department_name in table 1) and subtract the over_head_costs from table 2 so that I know how profitable a department is. Then I want to output the information like:
department_id, department_name, over_head_costs, product/department sales, total_profit.
I've been searching for like 2-3 hours. I've messed around with joins (which I'm pretty sure is how to solve this) and found the SUM function, which achieves summing (but not by department) and honestly, even if I'd seen the solution I wouldn't know it. I'm just really struggling to understand SQL.
SELECT SUM(products.product_sales), department_id, departments.department_name, over_head_costs
FROM products, departments
WHERE products.department_name = departments.department_name;
This is my most recent query and the closest I've gotten, except it only returns one department (I currently have 3).
This is roughly what I’d like it to look like:
Table 1 (products):
ID ITEM DEPARTMENT SALES
1 Hammer Tools 40
2. Nails Tools 40
3. Keyboard Computer 80
Table 2 (departments):
ID DEPARTMENT COST
1 Tools 20
2. Computer 30
Output:
ID DEPARTMENT COST SALES PROFIT
1 Tools 20 80 60
2. Computer 30 80 50
I'm not really sure what else to try. I think I'm just not understanding how joins and such work. Any help would be greatly appreciated.
You can try to use SUM wiht group by in a subquery. then do join.
Query 1:
SELECT d.*,
t1.SALES,
(t1.SALES - d.COST)PROFIT
FROM (
SELECT DEPARTMENT,SUM(SALES) SALES
FROM products
GROUP BY DEPARTMENT
) t1 JOIN departments d on d.DEPARTMENT = t1.DEPARTMENT
Results:
| DEPARTMENT | COST | SALES | PROFIT |
|------------|------|-------|--------|
| Tools | 20 | 80 | 60 |
| Computer | 30 | 80 | 50 |

How to get value as header field in pivot table?

I've been looking for this answer for hours without finding anything at all on this subject.
I'm trying to get a pivot table from the "Sells" table that displays :
- as header fields, the name of each seller in my shop
- as rows, each month of the year
- as data the sum of their sells for each month
The only issue I have is that the headers are populated with ID instead of the name of the sellers.
For example, instead of showing this :
Month | Steve | Joe
January | 5000$ | 600$
February | 400$ | 400$
It keeps showing the ID related to each seller:
Month | 1 | 2
January | 5000$ | 600$
February | 400$ | 400$
Here is my query :
TRANSFORM Sum(Sells.Ca) AS [Monthly sells]
SELECT DISTINCTROW Format$(Sells.DateSold,'mm - mmmm') AS Month
FROM Sells
GROUP BY Sells.DateSold
PIVOT Sells.Seller
Thank you very much for your help and your time.
EDIT:
As #WolfgangKais mentionned in the comments, I forgot to mention that the Seller field is a lookup field, that's why it only shows the first value of the lookup field, hence the ID and not the name.
As stated by #June7 and #Wolfgang Kais, I had to include the Sellers Table in the query in order to get each seller's name instead of their ID, thank you very much for the lead.
This was done by :
Constructing a temporary table containing rows populated by sellers name, amount sold and date of sell:
SELECT Sellers.Name AS Seller, Sells.Ca AS Amount, Sells.DateSold AS Month
FROM Sells
INNER JOIN Sellers ON Sells.Seller = Sellers.ID
Including this temporary table into my first pivot query (In the FROM part):
TRANSFORM SUM(TempTable.Amount) AS [Monthly Sells]
SELECT Format$(TempTable.Month, 'mm - mmmm') AS Month
FROM(
SELECT Sellers.Name AS Seller, Sells.Ca AS Amount, Sells.DateSold AS Month
FROM Sells
INNER JOIN Sellers ON Sells.Seller = Sellers.ID
) AS TempTable
GROUP BY Temptable.Month
PIVOT Temptable.Seller

Grouping values with IF, month-by-month, in a select statement

I am trying to run a report that will group by month the totals of expense accounts from an expense table which has the followings columns on each row:
expense_acc
debit
credit
post_date
The desired output of the report is in the following column format:
EXP ACC - JAN - FEB - MAR
This is my SQL select query:
SELECT expense_acc,
if(MONTH(post_date)=1,SUM(expenses.debit-expenses.credit),0) AS 'JAN',
if(MONTH(post_date)=2,SUM(debit-credit),0) AS 'FEB',
if(MONTH(post_date)=3,SUM(debit-credit),0) AS 'MAR'
FROM expenses
WHERE YEAR(expenses.entered)='2016'
GROUP BY expenses.expense_acc
The results are not grouping the expense values by month as expected. I am seeing grouping in the first row, regardless of the transaction date.
You have two parts to your requirement.
A month-by-month aggregate of your table's contents
A pivot table rendering, in which you pivot by-month rows to lie in columns.
Also, SUM(expenses.debit-expenses.credit) isn't resilient if the debit or credit columns ever contain NULL values.
Also, YEAR(date) defeats any index on date.
If you're wise you'll handle these requirements in two steps. For one thing, it will be easier to troubleshoot your results. For another, the next person who comes along will better understand your project.
The month-by-month aggregate:
SELECT expense_acc, LAST_DAY(post_date) month_ending,
SUM(expenses.debit) - SUM(expenses.credit) as net_expenses
FROM expenses
WHERE post_date >= '2016-01-01'
AND post_date < '20016-12-31' + INTERVAL 1 DAY
GROUP BY expense_acc, LAST_DAY(post_date)
ORDER BY expense_acc, LAST_DAY(post_date)
This will give you a row for each account and date. The row will show the account, the month-ending date, and the net expenses. (I don't understand expenses.entered in your example. It's best to filter on the same date you use to make your aggregate.) Your auditors will appreciate this separation of logic.
Next, you can use this as a subquery, to make your pivot display.
That's pretty straightforward:
SELECT expense_acc,
SUM(IF(MONTH(month_ending)=1,net_expenses,0)) as jan,
SUM(IF(MONTH(month_ending)=2,net_expenses,0)) as feb,
SUM(IF(MONTH(month_ending)=3,net_expenses,0)) as mar,
...
FROM (
SELECT expense_acc, LAST_DAY(post_date) month_ending,
SUM(expenses.debit) - SUM(expenses.credit) as net_expenses
FROM expenses
WHERE post_date >= '2016-01-01'
AND post_date < '20016-12-31' + INTERVAL 1 DAY
) z
GROUP BY expense_acc
ORDER BY expense_acc
But, you may want to do the pivoting in a client program. It's notoriously hard to write and maintain MySQL pivot code.
SELECT
SUM(JAN) AS JAN,
SUM(FEB) AS FEB
SUM(MAR) AS MAR
FROM
(
SELECT expense_acc,
if(MONTH(post_date)=1,SUM(expenses.debit-expenses.credit),0) AS 'JAN',
if(MONTH(post_date)=2,SUM(debit-credit),0) AS 'FEB',
if(MONTH(post_date)=3,SUM(debit-credit),0) AS 'MAR'
FROM expenses
WHERE YEAR(expenses.entered)='2016'
GROUP BY expenses.expense_acc
)TMP
GROUP BY expense_acc
In my opinion, the optimal way is that:
SELECT expense_acc, MONTH(post_date) month_num, SUM(debit-credit) as total
FROM expenses
WHERE YEAR(expenses.entered) = '2016'
GROUP BY expenses.expense_account, MONTH(post_date)
That will give you something like
|expense account | mont_num | total |
-----------------------------------------
| 2345 | 1 | 50 |
-----------------------------------------
| 2345 | 2 | 30 |
-----------------------------------------
| 2346 | 1 | 45 |
...
Because if you are doing one if statement per month, you will get 12 ifs.
It's better to manage the format of rows in you controller.
Hope it will help you.

Complex MySQL statement to list fishing standings?

I'm trying to make a standings chart using multiple tables. One keeps tracks of meetings attended to, each meeting counting as 5 points and the other table keeps track of results of tournaments. This is a fishing club site.
I have the following so far and can show the meeting points in order but the tournament results separate from that. I'd like to find a single albeit complex SQL statement to list out current standings.
I need to show the angler name which I can grab separate from a different table, then each month's 5 points listed along with the tournament result amount from the results table, these are all added up to finally list the total from all tournaments and meetings.
SELECT aid, sum(here*5) as total
FROM rollcall GROUP BY aid ORDER BY total DESC
SELECT aid, weight, weight-penalty as fweight
FROM `results` where tid=2 order by fweight desc
So an example is:
place angler JAN FEB MARCH ... Total Points
1 name1 5 50 5 45 0 38 143
2 name2 5 49 5 47 5 31 142
...
Is that clear at all?
What if you build your query something like this?
SELECT aid,
sum(SELECT count(1) from meetings WHERE MONTH(columndatetime) = 1 * 5) AS JAN,
sum(SELECT count(1) from meetings WHERE MONTH(columndatetime) = 2 * 5) AS FEB,
/
-- add same logic to the rest of the months
/
sum(SELECT count(1) from meetings WHERE YEAR(columndatetime) = 2013 * 5) as total
FROM rollcall GROUP BY aid ORDER BY total DESC
Where columndatetime is the name of your column that has the date and time for the meetings etc...
The last one takes all for the year.
Could this help you out?

Query to eliminate multiple rows based on oldest date

Working in MS Access 2003 SP3: I have a query that I am running to find what 'cars' were sold with a date after the delivery date. I have thousands of rows. When it is all said and done, I want to just have a handful of rows for each 'car' and then the oldest date. Any suggestions?
CAR DATE ORDERED DATE DELIVERED CUSTOMER NUMBER DATE SOLD
FORD MUSTANG 20061002 20080413 ABC123 20080422
FORD MUSTANG 20061002 20080413 ABC124 20080429
CHEVY IMPALA 20061002 20080413 ABC125 20080505
This could be better if you had an ID field:
DELETE
FROM Cars
WHERE Cars.DATESOLD Not In (
SELECT TOP 5 DateSold
FROM Cars c
WHERE c.Car=Cars.Car
ORDER BY DateSold DESC)
And Cars.DATESOLD Not In (
SELECT TOP 1 DateSold
FROM Cars c
WHERE c.Car=Cars.Car
ORDER BY DateSold)
If there are duplicate dates, you will end up with more than 5 records.