How do I fix this SQL query (MariaDB) to produce the correct output? - mysql

I have been trying to extract some data from a database and produce the correct output. The following is what I am looking for
id | ref_no | Order time | discount code | total | items | donations
This is my SQL query so far:
SELECT
order.id,
order.ref_no,
order.cdate AS "Order time",
order.promocode AS "discount code",
order.orig_total as "total",
GROUP_CONCAT(order_item_ref.item_id ORDER BY order_item_ref.item_id) AS "items",
(CASE WHEN order_item_ref.item_id = "99"
THEN order_item_ref.quantity ELSE "0" END) AS "donations"
FROM `order`
INNER JOIN `order_item_ref`
ON order.id = order_item_ref.order_id
WHERE order.deleted = "0"
GROUP BY order.id;
Currently it doesn't quite work. The donation column is supposed to show 0 when an order does not contain an item with the item number 99 or the actual amount (order_item_ref.quantity) if it does. However the query only works sometimes to produce something like the following:
If I drop by the GROUP BY and GROUP CAT parts the query works as intended, however I need to keep the grouping intact.
How can I fix the query so the output is correct?
Edit: the output for line 48 is correct. The output for line 49 is not. There should be a non-zero number for the right hand column which should come from order_item_ref.quantity as per the SQL query above.

Since the question has been reopened I can post my own answer. After the explanation made by KIKO Software, I was looking for a way to aggregate (CASE WHEN order_item_ref.item_id = "99" THEN order_item_ref.quantity ELSE "0" END) AS "donations" and found that I was able to do it by simply summing over the output like so:
SUM((CASE WHEN order_item_ref.item_id = "99" THEN order_item_ref.quantity ELSE "0" END)) AS "donations"

Related

How to pivot table in MySql?

I have a table illustrated on the attached screen:
And data is presented:
As you can see it contains all fields from lines (value, column_id - is field type). Each field has line_index and column_index of position and column_id.
I want to get back all lines with all field names like:
line_index column_id_1 column_name1 column_id_2 column_name2 column_id_3 column_name3
0 1 Age 2 Vasile 3 NY
More simply I need to build all fields(rows) to columns then to lines back.
Should I use Pivot and is it possible in MySQL?
Link to sqlfiddle
You will need to group the results by line_index and conditionally transform rows to columns.
SELECT l.line_index,
MAX(CASE WHEN ct.column_name = "NAME" THEN l.value ELSE NULL END) AS "NAME" ,
MAX(CASE WHEN ct.column_name = "AGE" THEN l.value ELSE NULL END) AS "AGE" ,
MAX(CASE WHEN ct.column_name = "ZUP" THEN l.value ELSE NULL END) AS "ZUP"
FROM columns_types ct
LEFT JOIN `lines` l ON l.column_id = ct.column_id
GROUP BY l.line_index;
Try it here. Also I did some changes in your schema which I felt didn't impact the data stored in the tables. You were adding redundant rows(perhaps) in your columns_types table. And by looking at the query, you know that you will have to build a MAX(CASE statement for each column, so its best if you first fetch it and then build the final query in some programming language.

SQL : SELECT SUM WHERE CONDITION

I've got some troubles about SQL request :
I have a table like this table data image
I would like to create a view from this table to get :
Time_A : SUM of a column (total_time_taken) WHERE column (is_radiant)=1
Time_B : SUM of the same column (total_time_taken) WHERE column (is_radiant)=0
Time_AB : SUM of the column (total_time_taken) WHERE column (is_radiant)=0 OR (is_radiant)=1
SELECT
SUM(`matchpickban_radiant`.`total_time_taken`) AS `draft_time_radiant`,
SUM(`matchpickban_dire`.`total_time_taken`) AS `draft_time_radiant`
FROM
(`matchpickban` AS `matchpickban_radiant`
JOIN `matchpickban` AS `matchpickban_dire` ON ((`matchpickban_dire`.`idmatchpickban` = `matchpickban_radiant`.`idmatchpickban`)))
WHERE
`matchpickban_radiant`.`is_radiant` = 1
AND `matchpickban_dire`.`is_radiant` = 0
Actually I can run this request without syntax error but the result is NULL cause no data can be equal to 0 AND equal to 1 in the same time, obviously...
Also, I don't know if it's possible to make a JOIN the table to itself as I did (matchpickban JOIN matchpickban).
If syntax is correct I need to place my WHERE CONDITION away but don't know how, is it possible to replace it with 2 IF statement (IF is_radiant=0 SUM(...))
Thx for reading and helping me about this issue I got !
If you need more info about table or request I will give you all you need !
No need for a self-join or complex logic, you can just use conditional aggregation, which consists in using conditional expression within aggregate functions.
In MySQL, you could go:
select
sum(is_radiant * total_time_taken) time_a,
sum((1 - is_radiant) * total_time_taken) time_b,
sum(total_time_taken) time_ab
from matchpickban
where is_radiant in (0, 1)
This works because is_radiant is made of 0/1 values only - so this simplifies the logic. A more canonical way to phrase the conditional sums would be:
sum(case when is_radiant = 1 then total_time_taken else 0 end) time_a,
sum(case when is_radiant = 0 then total_time_taken else 0 end) time_b,

IF with SUM produces incorrect results in MySQL

I am getting incorrect results when I try to insert a SUM into an IF clause. The results are correct when I use COUNT, either incorrect or NULL when I use SUM. I have been able to produce the correct results for each statement through another query (as a means of validating the formula). What is the syntax to get correct results for an SUM within an IF statement? Based on another StackOverflow question, I attempted to fix the formula, but it produced an error.
SELECT
IF (Artist LIKE '%Hillsong%' , 'Hillsong', NULL ) as Artist,
COUNT(IF(CCD BETWEEN 28 AND 730,1,NULL)) AS 1_CC, -- result 191, which is correct
IF(CCD BETWEEN 28 AND 730, SUM(CC28),NULL) AS 2_CC, -- result NULL, should be 610 xx
COUNT(IF(CCD > 28,1,NULL)) AS 3_CC, -- result 684, which is correct
COUNT(IF(CCD < 730,1,NULL)) AS 4_CC, -- result 502, which is correct
IF(CCD > 28,SUM(CC28),NULL) AS 5_CC, -- result 2253, should be 1882 xx
--- SUM(IF(CCD > 28,CC28,NULL) AS 6_CC, -- my attempt to fix, creates error
IF(CCD < 730,SUM(CC28),NULL) AS 7_CC -- result NULL, shoul be 981 xx
FROM praisecharts_reporting.large_sales_report
GROUP BY 1;
As a frame of reference, I am a music publisher, and I am trying to get results for all songs where the artist includes "Hillsong", where the Chord Chart (CC) has been available between 28 and 730 days (CCD BETWEEN 28 AND 730). The COUNT should tell me how many song titles qualify, and SUM should tell me the total unit sales for all songs that qualify.
I figured out the answer to my problem. The syntax for putting an IF clause inside a SUM is to use CASE WHEN. Below is the solution to my query above, and it produces correct results all around:
SELECT
IF (Artist LIKE '%Hillsong%' , 'Hillsong', NULL ) as Artist,
COUNT(IF(CCD BETWEEN 28 AND 730,1,NULL)) AS 1_CC,
SUM(CASE WHEN CCD BETWEEN 28 AND 730 THEN CC28 ELSE 0 END) AS 2_CC,
COUNT(IF(CCD > 28,1,NULL)) AS c3_CC,
COUNT(IF(CCD < 730,1,NULL)) AS c4_CC,
SUM(CASE WHEN CCD > 28 THEN CC28 ELSE 0 END) AS 5_CC,
SUM(CASE WHEN CCD < 730 THEN CC28 ELSE 0 END) AS 6_CC
FROM praisecharts_reporting.large_sales_report
GROUP BY 1;
You should be on the right track on your attempt to use SUM - IF
--- SUM(IF(CCD > 28,CC28,NULL) AS 6_CC, -- my attempt to fix, creates error
If you look closely, you are missing an ending parenthesis. We must pay attention to the error we received. Most likely you received a syntax error right after AS 6_CC,.
Just add a closing parenthesis after NULL:
SUM(IF(CCD > 28,CC28,NULL)) AS 6_CC,
Try to use SUM - IF on your other columns as well. Let me know if this works.
With SUM - IF you can have a true / false result, which is as simple as it can be (though you can have nested if's inside, but that would make it unreadable).
With SUM - CASE you have an option to have more results by providing more conditions, just like a SWITCH statement.
Without the underlying data it would be hard to verify the results. But your NULL result may be due to a underlying NULL in data or due to condition clause.
Try replacing SUM(CC28) with SUM(IFNULL(CC28,0))
A sum of Integer and NULL equals NULL. Hence you might be getting NULL in second set.

How to make a select that returns 4 totals from same table but with different filters

I'm trying to make a report in SSRS where I show some totals from the same table. I know I can use selects into select, but I've heard that could affect the performance and make it slow. That is why I decided to use store procedures but I'm not so familiar with it (I only did some basic SP) so some help will be apreciated:
This is what I need to get:
|--------------|------------------------- TOTALS AND PERCENTAGES ----------------------|
|COMPANY | PACKAGES | WEIGHT | PACKAGE_DELIVERED |% DELIVERED | ONTIME |% ONTIME |
These are the querys I did in a previous version of the report (using asp):
SELECT COMPANY_NAME, COUNT(ID) AS PACKAGES, SUM(WEIGHT) AS WEIGHT
FROM PACKAGE
WHERE ACTUAL_DELIVERY_DATE BETWEEN 'X' AND 'Y'
GROUP BY COMPANY_CODE, COMPANY_NAME
Then I put the results in arrays and then make a new select to get the rest of information adding the COMPANY as filter:
SELECT COMPANY_CODE, ESTIMATED_DELIVERY_DATE, ACTUAL_DELIVERY_DATE
FROM PACKAGE
WHERE ACTUAL_DELIVERY_DATE BETWEEN 'X' AND 'Y'
AND STATUS = 'DELIVERED'
AND COMPANY_CODE = 'DHL'
ORDER BY STATUS
For every row
PACKAGES_DELIVERED = + 1
IF ACTUAL_DELIVERY_DATE < ESTIMATED_DELIVERY_DATE THEN ONTIME = + 1
Next
Then I calculate the percentages and show all together in a table.
Somebody that can help me to put all this in a Store Procedure or maybe have another idea.
Thanks in advance.
I would add the following columns to the original SELECT, using SUM on a CASE statement:
, SUM ( CASE WHEN STATUS = 'DELIVERED' THEN 1 ELSE 0 END ) AS PACKAGES_DELIVERED
, SUM ( CASE WHEN STATUS = 'DELIVERED' AND ACTUAL_DELIVERY_DATE < ESTIMATED_DELIVERY_DATE THEN 1 ELSE 0 END ) AS ONTIME
This doesnt seem complex enough to bother with a Stored Procedure.

SQL - Query same column twice with different dates in where clause

I have tried searching all over for answers but none have answered my exact issue. I have what should be a relatively simple query. However, I am very new and still learning SQL.
I need to query two columns with different dates. I want to return rows with the current number of accounts and current outstanding balance and in the same query, return rows for the same columns with data 90 days prior. This way, we can see how much the number of accounts and balance increased over the past 90 days. Optimally, I am looking for results like this:
PropCode|PropCat|Accts|AcctBal|PriorAccts|PriorBal|
----------------------------------------------------
77 |Comm | 350 | 1,000| 275 | 750
Below is my starting query. I realize it's completely wrong but I have tried numerous different solution attempts but none seem to work for my specific problem. I included it to give an idea of my needs. The accts & AcctBal columns would contain the 1/31/14 data. The PriorAcct & PriorBal columns would contain the 10/31/13 data.
select
prop_code AS PropCode,
prop_cat,
COUNT(act_num) Accts,
SUM(act_bal) AcctBal,
(SELECT
COUNT(act_num)
FROM table1
where date = '10/31/13'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
)
AS PriorAccts,
(SELECT
SUM(act_bal)
FROM table1
where date = '10/31/13'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
)
AS PriorBal
from table1
where date = '01/31/14'
and Pro_Group in ('BB','FF')
and prop_cat not in ('retail', 'personal')
and Not (Acct_Code = 53 and ACTType in (1,2,3,4,5,6,7))
group by prop_code, prop_cat
order by prop_cat
You can use a CASE with aggregates for this (at least in SQL Server, not sure about MySQL):
...
COUNT(CASE WHEN date='1/31/14' THEN act_num ELSE NULL END) as 'Accts'
,SUM(CASE WHEN date='1/31/14' THEN act_bal ELSE NULL END) as 'AcctBal'
,COUNT(CASE WHEN date='10/31/13' THEN act_num ELSE NULL END) as 'PriorAccts'
,SUM(CASE WHEN date='10/31/13' THEN act_bal ELSE NULL END) as 'PriorAcctBal'
....
WHERE Date IN ('1/31/14', '10/31/13')