display column in horizontal format - mysql

I have a table as follows.
[Date] [Test_Item] [Result]
1/2/2014 A 1.1
2/2/2014 B 31.1
3/2/2014 C 20
5/2/2014 A 44
i would like display in the following format
[Test_Item] 1/2/2014 2/2/2014 3/2/2014 5/2/2014
A 1.1
B 31.1
C 20
A 44
How can i achieve this? please suggest the query in this case.

This is a basic use of the case statement:
select test_item,
(case when `date` = '1/2/2014' then result end) as `1/2/2014`,
(case when `date` = '2/2/2014' then result end) as `2/2/2014`,
(case when `date` = '3/2/2014' then result end) as `3/2/2014`,
(case when `date` = '5/2/2014' then result end) as `5/2/2014`
from table t;
You don't mention anything about types. If date is actually stored as a date or date/time (as it should be), then you should use ISO standard date formats for comparison, which assuming your format is d/m/yyyy, would be:
select test_item,
(case when `date` = '2014-02-01' then result end) as `1/2/2014`,
(case when `date` = '2014-02-02' then result end) as `2/2/2014`,
(case when `date` = '2014-02-03' then result end) as `3/2/2014`,
(case when `date` = '2014-02-05' then result end) as `5/2/2014`
from table t;

Related

How to change the mysql query to retrieve data (pivot view)

I have a dataset as follows,
I need to get the average xdr_count of each table_name for 7 past days..So I tried as below.
SELECT
t1.table_date,
t1.table_name,
t1.xdr_count,
t2.AVG_XDR,
t2.Threshold
FROM stat t1
INNER JOIN
(
SELECT table_name, AVG(xdr_count) AS AVG_XDR,AVG(xdr_count)*.8 as Threshold
FROM stat
where table_date >= DATE(NOW() - INTERVAL 7 DAY)
GROUP BY table_name
) t2
ON t2.table_name = t1.table_name
where table_date >= DATE(NOW() - INTERVAL 7 DAY);
This works fine and I could get the output as below.
But I need to rearrange this table to a pivot view(hope this can called as pivot view) such as below.
I need to mention the table name,Avg(XDR) and dates with appropraite xdr_count values.
Can someone help me to change the view of output result..
Note: Threshold value will be use later.
I'm not entirely sure how you want to calculate the avg_xdr columns. But, you can try something like this.
SELECT table_name,
MAX(CASE WHEN table_date = '2022-08-21' then avg_xdr else 0 END) AS avg_xdr,
MAX(CASE WHEN table_date = '2022-08-21' then xdr_count else 0 END) AS '2022-08-21',
MAX(CASE WHEN table_date = '2022-08-22' then xdr_count else 0 END) AS '2022-08-22',
MAX(CASE WHEN table_date = '2022-08-23' then xdr_count else 0 END) AS '2022-08-23',
MAX(CASE WHEN table_date = '2022-08-24' then xdr_count else 0 END) AS '2022-08-24'
FROM tableA
Group by table_name
db fiddle

CASE query optimization

SELECT
COUNT(CASE WHEN VALUE = 1 THEN 1 END) AS score_1,
COUNT(CASE WHEN VALUE = 2 THEN 1 END) AS score_2,
COUNT(CASE WHEN VALUE = 3 THEN 1 END) AS score_3,
COUNT(CASE WHEN VALUE = 4 THEN 1 END) AS score_4,
COUNT(CASE WHEN VALUE = 5 THEN 1 END) AS score_5,
COUNT(CASE WHEN VALUE = 6 THEN 1 END) AS score_6,
COUNT(CASE WHEN VALUE = 7 THEN 1 END) AS score_7,
COUNT(CASE WHEN VALUE = 8 THEN 1 END) AS score_8,
COUNT(CASE WHEN VALUE = 9 THEN 1 END) AS score_9,
COUNT(CASE WHEN VALUE = 10 THEN 1 END) AS score_10
FROM
`answers`
WHERE
`created_at` BETWEEN '2017-01-01 00:00:00' AND '2019-11-30 23:59:59'
Is there a way to optimize this query, because I have 4 million answer records in my DB, and it runs very slowly?
Try running this one time to create an index:
CREATE INDEX ix_ca on answers(created_at)
That should speed your query up. If you are curious about why, see here:
What is an index in SQL?
You could try add a redundant composite index
create idx1 on table answers(created_at, value)
using redudance in index the query should be result without accessing to table data just using the index content
Want it to be 10 times as fast? Use the Data Warehousing technique of buiding and maintaining a "Summary table". In this example the summary table might be
CREATE TABLE subtotals (
dy DATE NOT NULL,
`value` ... NOT NULL, -- TINYINT UNSIGNED ?
ct SMALLINT UNSIGNED NOT NULL, -- this is 2 bytes, max 65K; change if might be bigger
PRIMARY KEY(value, dy) -- or perhaps the opposite order
) ENGINE=InnoDB
Each night you summarize the day's data and build 10 new rows in subtotals.
Then the "report" query becomes
SELECT
SUM(CASE WHEN VALUE = 1 THEN ct END) AS score_1,
SUM(CASE WHEN VALUE = 2 THEN ct END) AS score_2,
SUM(CASE WHEN VALUE = 3 THEN ct END) AS score_3,
SUM(CASE WHEN VALUE = 4 THEN ct END) AS score_4,
SUM(CASE WHEN VALUE = 5 THEN ct END) AS score_5,
SUM(CASE WHEN VALUE = 6 THEN ct END) AS score_6,
SUM(CASE WHEN VALUE = 7 THEN ct END) AS score_7,
SUM(CASE WHEN VALUE = 8 THEN ct END) AS score_8,
SUM(CASE WHEN VALUE = 9 THEN ct END) AS score_9,
SUM(CASE WHEN VALUE = 10 THEN ct END) AS score_10
FROM
`subtotals`
WHERE `created_at` >= '2017-01-01'
AND `created_at` < '2019-12-01'
Based on what you have provided, there will be about 10K rows in subtotals; that's a lot less to wade through than 4M rows. It might run more than 10 times as fast.
More discussion: http://mysql.rjweb.org/doc.php/summarytables

MySQL : using sum in( case when ) statement shows 0 as result

new to MySQL..so pls help me out with this basic code..
i have a query something like this...
select weekofyear(id_time),
(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
and it gives correct results as--here
however i want to use sum after case when statement so that I can get total values where BO=1 and group by week of year , so i made following changes-
select weekofyear(id_time),
count(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
sum(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
group by weekofyear(id_time)
but it always returns 0 as output.
Output --here 2
Please help , I don't know what am I doing wrong here.
Thanx !
As others have already said, session variables can be unpredictable (especially when aggregation gets mixed in). That said, it doesn't look like you're using the session variables to carry over values from one row to the next (as is often done), but to just make aliases of sorts for calculations you don't want to repeat.
A better way to handle that is just through subqueries.
SELECT woy, id, Tat1, Tat2, check1, check2
, CASE
WHEN check2=0 THEN (
CASE
WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+10))) THEN 1
ELSE 0
END
)
ELSE (
CASE WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+20))) THEN 1
ELSE 0
END
)
END AS BO
FROM (
SELECT WEEKOFYEAR(id_time) AS woy
, id
, exp1 AS Tat1
, exp2 AS Tat2
, exp3 AS check1
, exp4 AS check2
FROM datb
WHERE cid=18
AND id_time BETWEEN '2019-11-01 06:00:00' AND '2019-11-25 06:00:00'
) AS subQ
;
You can then tweak the above query for aggregation, or use it as a subquery for an aggregating outer query.

mysql query split column into m

I have the following database structure:
FieldID|Year|Value
a|2011|sugar
a|2012|salt
a|2013|pepper
b|2011|pepper
b|2012|pepper
b|2013|pepper
c|2011|sugar
c|2012|salt
c|2013|salt
now I would like to run a query that counts the number of fields for every item in the particular year looking something like this:
value|2011|2012|2013
sugar|2|0|0
salt |0|2|1
pepper|1|1|2
I used multiple tables for every year before. However the distinct values for 2011,2012 and 2013 might be different (e.g. sugar would only be present in 2011)
For individual years I used:
SELECT `Value`, COUNT( `FieldID` ) FROM `Table` WHERE `Year`=2011 GROUP BY `Value`
A1ex07's answer is fine. However, in MySQL, I prefer this formulation:
SELECT Value,
sum(`Year` = 2011) AS cnt2011,
sum(`Year` = 2012) AS cnt2012,
sum(`Year` = 2013) AS cnt2013
FROM t
GROUP BY value;
The use of count( . . . ) produces the correct answer, but only because the else clause is missing. The default value is NULL and that doesn't get counted. To me, this is a construct that is prone to error.
If you want the above in standard SQL, I go for:
SELECT Value,
sum(case when `Year` = 2011 then 1 else 0 end) AS cnt2011,
sum(case when `Year` = 2012 then 1 else 0 end) AS cnt2012,
sum(case when `Year` = 2013 then 1 else 0 end) AS cnt2013
FROM t
GROUP BY value;
You can do pivoting :
SELECT `Value`,
COUNT(CASE WHEN `Year` = 2011 THEN FieldID END) AS cnt2011,
COUNT(CASE WHEN `Year` = 2012 THEN FieldID END) AS cnt2012,
COUNT(CASE WHEN `Year` = 2013 THEN FieldID END) AS cnt2013
FROM `Table`
GROUP BY `Value`
It is called Pivot Table, achieve with a chain of CASE statements which apply a 1 or 0 for each condition, then SUM() up the ones and zeros to retrieve a count.
SELECT
Value,
SUM(CASE WHEN Year = 2011 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2012 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2013 THEN 1 ELSE 0 END) AS 2013
FROM Table
GROUP BY Value

MySQL using Sum and Case

I'm trying to create a GridView with ASP.NET connecting to a MySQL database. The data appears like below.
BusinessUnit OrderDate Canceled
UnitA 1/15/2013 N
UnitA 10/1/2013 N
UnitB 10/15/2013 N
UnitB 10/22/2013 N
UnitB 10/22/2013 N
Based on the records above, I'd like the result to appear like below
BusinessUnit TodaysOrders ThisMonthsOrders ThisYearsOrders
UnitA 0 1 2
UnitB 2 3 3
My current code is below. It's giving me error (something about DatabaseName.sum does not exist. Check the
Function Name Parsing and Resolution' section... )
Select
SUM (CASE WHEN (OrderDate)=DATE(NOW()) THEN 1 ELSE 0 END) AS TodaysOrders,
SUM (CASE WHEN YEAR(OrderDate) = YEAR(CURDATE()) AND MONTH(OrderDate) = MONTH(CURDATE()) THEN 1 ELSE 0 END) AS ThisMonthsOrders,
SUM (CASE WHEN YEAR(main_order_managers.creation_date) = YEAR(CURDATE()) THEN 1 ELSE 0 END) AS ThisYearsOrders
code continues
FROM OrderTable WHERE OrderTable.Canceled. <> 'Y';
Is Sum Case the best use here?
The error is caused by the space between function name and parenthesis
SUM (CASE WHEN ...
^^
Read more Function Name Parsing and Resolution
Try
SELECT BusinessUnit,
SUM(CASE WHEN OrderDate = CURDATE() THEN 1 ELSE 0 END) TodaysOrders,
SUM(CASE WHEN DATE_FORMAT(OrderDate, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m') THEN 1 ELSE 0 END) ThisMonthsOrders,
SUM(CASE WHEN YEAR(OrderDate) = YEAR(CURDATE()) THEN 1 ELSE 0 END) ThisYearsOrders
FROM OrderTable
WHERE Canceled <> 'Y'
GROUP BY BusinessUnit
Here is SQLFiddle demo