MYSQL - Rows to columns transpose [duplicate] - mysql

This question already has answers here:
MySQL - Rows to Columns
(13 answers)
Closed 1 year ago.
I've looked at similar posts (specifically MySQL - Rows to Columns), and from that wrote the MYSQL statement below in an effort to correctly transpose rows to columns. The transposition works for the most part, but only one IT.TaxStatus is selected and given for each row (that is for each IT.ClientCode), and I cannot for the life of me figure out why.
SELECT IT.ClientCode,
CASE WHEN IT.TaxYear='2021' THEN IT.TaxStatus ELSE NULL END AS '2021',
CASE WHEN IT.TaxYear='2020' THEN IT.TaxStatus ELSE NULL END AS '2020',
CASE WHEN IT.TaxYear='2019' THEN IT.TaxStatus ELSE NULL END AS '2019',
CASE WHEN IT.TaxYear='2018' THEN IT.TaxStatus ELSE NULL END AS '2018'
FROM IT GROUP BY IT.ClientCode
Order by IT.ClientCode;
My original table:
Original table
Expected result:
Expected Result
Do anyone have an explanation why only one IT.TaxStatus per IT.ClientCode would be given in the final recordset, and not all the years?
Thank you for your assistance!
Regards
Wessel

You need to add an aggregation function
SELECT IT.ClientCode,
MAX(CASE WHEN IT.TaxYear='2021' THEN IT.TaxStatus ELSE NULL END) AS '2021',
MAX(CASE WHEN IT.TaxYear='2020' THEN IT.TaxStatus ELSE NULL END) AS '2020',
MAX(CASE WHEN IT.TaxYear='2019' THEN IT.TaxStatus ELSE NULL END) AS '2019',
MAX(CASE WHEN IT.TaxYear='2018' THEN IT.TaxStatus ELSE NULL END) AS '2018'
FROM IT
GROUP BY IT.ClientCode
Order by IT.ClientCode;

Related

Use a generated column in MariaDB 5.5.52

I have a valid sql statement that looks like this:
SELECT SUM(CASE WHEN faell_art='monatlich' THEN betrag*12 END) + SUM(CASE WHEN faell_art='vierteljährlich' THEN betrag*4 END) + SUM(CASE WHEN faell_art='halbjährlich' THEN betrag*2 END) + SUM(CASE WHEN faell_art='jährlich' THEN betrag END) as total FROM banking
Now I want to create a generated column which does exactly the same. I tried this statement:
ALTER TABLE `banking` ADD `test` DECIMAL(10,2) AS (SUM(CASE WHEN faell_art='monatlich' THEN betrag*12 END) + SUM(CASE WHEN faell_art='vierteljährlich' THEN betrag*4 END) + SUM(CASE WHEN faell_art='halbjährlich' THEN betrag*2 END) + SUM(CASE WHEN faell_art='jährlich' THEN betrag END)) AFTER `kommentar`;
However it doesn´t work ("#1901 - Function or expression is not allowed for column 'test'").
Any help? Thx :-)
There is a limitation:
subqueries or anything that depends on data outside the row are not
allowed (these are not deterministic because the underlying data can
change).
All aggregate functions (SUM,...) operate with other records in the table.
Virtual (Computed) Columns.
So, that generated column cannot be created. Or, you could create a view.

How to group same kind of values into common one and group by that

Hi I was looking for a mysql query result like
As you can see there are some values have the kind of values (Ex: BV and BR or C5 and C7) how can I combine then together into one common value lets say B or C and group by that in sql?
I have the following query:
SELECT
type,
sum(case when status ='valid' then 1 else 0 end) valid_jobs,
sum(case when status ='non-valid' then 1 else 0 end) non_valid_jobs,
sum(case when status IS NULL then 1 else 0 end) null_jobs
from
main_table
where
SUBSTRING_INDEX(CAST(CAST(from_unixtime(date_generated) AS DATE) AS CHAR), '-',2) REGEXP '^2016'
group by type
Thanks in advance guys.
Otcome will look like:
Just use an expression that evaluates the value of the type column, and returns the desired result.
What's not clear from the question is the "mapping" from type to the value you want returned in the first column. It looks like we might be looking at just the first character of value in the type column.
SUBSTR(type,1,1)
If the "mapping" is more involved, then we could use a CASE expression. For example:
CASE
WHEN type IN ('BV','BR','BT','ZB') THEN 'B'
WHEN type IN ('C5','C7') THEN 'C'
WHEN ... THEN ...
ELSE type
END
We'd use that as the first expression in the SELECT list (replacing the reference to the type column in the original query), and in the GROUP BY clause.
On an (unrelated) performance note, we'd prefer conditions in the WHERE clause to be on bare columns. That allows MySQL to make use of an (efficient) range scan operation on an appropriate index.
With this condition:
WHERE SUBSTRING_INDEX(CAST(CAST(FROM_UNIXTIME( t.date_generated ) AS DATE) AS CHAR), '-',2)
REGEXP '^2016'
We're forcing MySQL to evaluate the expression on the left side for every row in the table. And the value returned by the expression is compared.
If what we're really trying to do is get date_generated values in 2016, assuming that date_generated is INTEGER type, storing 32-bit unix-style number of seconds since beginning of the era 1970-01-01...
We can do something like this:
WHERE t.date_generated >= UNIX_TIMESTAMP('2016-01-01')
AND t.date_generated < UNIX_TIMESTAMP('2017-01-01')
MySQL will see that as a range operation on the values in te date_generated column. And with that, MySQL can make effective use of an index that has date_generated as a leading column.
Just replace expr with the expression that returns the values you want in the first column:
SELECT expr
, SUM(IF( t.status = 'valid' ,1,0)) AS valid_jobs
, SUM(IF( t.status = 'non-valid' ,1,0)) AS non_valid_jobs
, SUM(IF( t.status IS NULL ,1,0)) AS null_jobs
FROM main_table t
WHERE t.date_generated >= UNIX_TIMESTAMP('2016-01-01')
AND t.date_generated < UNIX_TIMESTAMP('2017-01-01')
GROUP BY expr
EDIT
To guarantee that rows are returned in a particular sequence, add an ORDER BY clause, e.g.
ORDER BY 1
try this,
SELECT
LEFT(type,1) AS type,
sum(case when status ='valid' then 1 else 0 end) valid_jobs,
sum(case when status ='non-valid' then 1 else 0 end) non_valid_jobs,
sum(case when status IS NULL then 1 else 0 end) null_jobs
FROM
main_table
WHERE
SUBSTRING_INDEX(CAST(CAST(from_unixtime(date_generated) AS DATE) AS CHAR), '-',2) REGEXP '^2016'
GROUP BY
type

Case statement for a date field with Mysql db

Iam trying to do a CASE statement. The requirement is if Date field is NULL then show it as 'Pending' or else show the date from the db.
I have tried the below case statement but there is some problem.
CASE po_amend_received_date IS NULL WHEN 1 THEN 'Pending'
ELSE po_amend_received_date END AS `po_amend_received_date`
Am i making any mistake here?
CASE WHEN po_amend_received_date IS NULL THEN 'Pending'
else po_amend_received_date
end as `po_amend_received_date`

Using Sum inside a Case statement in MySQL

I am having problem in MySQL adding three values, this should be simple right?
I have code that selects values from a column based upon the value of a second column, I use a case statement like this:
Select
Max(Case
When Table1.costcode Like '%Costcode1%'
Then Table1.costs
Else Null End) As 'Costcode1',
Max(Case
When Table1.costcode Like '%Costcode2%'
Then Table1.costs
Else Null End) As 'Costcode2',
Max(Case
When Table1.costcode Like '%Costcode3%'
Then Table1.costs
Else Null End) As 'Costcode3',
(Case
When Table1.costcode In ('%Costcode1%','%Costcode2%','%Costcode3%')
Then Sum(Table1.costs)
Else Null End) As 'Total Cost',
From Table1
the first three Case statements work fine and all return values (these are held in the database as negative numbers e.g. -13624.00), however the Total Cost Case just returns Null...
The column Table1.costcode includes many other codes as well so I can't just sum all of the values without picking them out first.
It must be simple to sum these values, but obviously I'm missing something… Help, please :-)
Thanks
Try this -
SUM(Case Table1.costcode
When LIKE ('%Costcode1%') Then Table1.costs
When LIKE ('%Costcode2%') Then Table1.costs
When LIKE ('%Costcode3%') Then Table1.costs
Then Table1.costs
Else 0.00 End) As 'Total Cost'

trouble with WHEN NOT NULL

I want to create a switch around the following. I've tried various permutations but I just cant get IS NOT NULL to work.
(CASE billing_code WHEN NOT NULL THEN billing_amount END) AS Billing Amount
Thanks in advance
You need to use the "searched" form of the CASE statement. Additionally as the column alias contains spaces it needs to be delimited as below.
CASE WHEN billing_code IS NOT NULL THEN billing_amount END AS [Billing Amount]
Try as below
(Case When billing_code is Not Null then billing_amount End) As "Billing Amount"