Mysql rows to columns query - mysql

I am hoping this is a relatively simple question to answer. I have a list of transactions in a database table and I want to extract into columns an enum value (y/n) to each motorcycle manufacturer that exists in that table.
I have tried the following query:
SELECT
accCode,
rnFuncBool(accCode,'HON') purchasedHonda,
rnFuncBool(accCode,'YAM') purchasedYamaha,
rnFuncBool(accCode,'KAW') purchasedKawsaki,
rnFuncBool(accCode,'SUZ') purchasedSuzuki,
rnFuncBool(accCode,'DUC') purchasedDucati,
rnFuncBool(accCode,'KTM') purchasedKTM,
rnFuncBool(accCode,'SYM') purchasedSym,
rnFuncBool(accCode,'VIC') purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' GROUP BY accCode
and the function rnFuncBool is as follows:
DELIMITER $$
USE `phcontacts`$$
DROP FUNCTION IF EXISTS `rnFuncBool`$$
CREATE DEFINER=`root`#`localhost` FUNCTION `rnFuncBool`(
fnAccCode VARCHAR(6),
fnAccMan VARCHAR(3)
) RETURNS VARCHAR(1) CHARSET utf8
BEGIN
IF (SELECT COUNT(*) FROM _emarsys_vehiclessold WHERE accCode=fnAccCode COLLATE utf8_unicode_ci AND vehichleManufacturer=fnAccMan COLLATE utf8_unicode_ci )>0 THEN
RETURN 'y';
ELSE
RETURN 'n';
END IF;
END$$
DELIMITER ;
Whilst this seems a really logical solution for a quick return the main table contains over 48,000 rows and so the execution time is in the minutes.
I did try working with a join on a temporary table but that only returned one manufacturer when grouped by the customer account code.
Of course I could try group_concat but that is not what I really want to achieve.
If anybody has any thoughts on how I can achieve this that would be brilliant.
As always many thanks in advance.
Cheers
Graham

If you go for boolean 1/0 instead of y/n then you can greatly simplify things for yourself and do a cross-tab problem query which'll be way more efficient...
SELECT
accCode,
SUM(CASE WHEN accCode ='HON' THEN 1 ELSE 0 END) purchasedHonda,
SUM(CASE WHEN accCode='YAM' THEN 1 ELSE 0 END) purchasedYamaha,
...
SUM(CASE WHEN accCode='VIC' THEN 1 ELSE 0 END) purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>''
GROUP BY accCode
That being said, your code and what I've shown an abridged amendment to is grouping by accCode, which is what you've said you want, but I'm not sure how much value there is for you unless you're looking to construct a lookup table or something similar in which case you could simply get a list of distinct accCode and do the rest by hand or in excel just as quickly as writing sql to do it.

Whenever you get "looping" like this in a design, there is frequently a much more efficient design.
It's hard to figure out why you would need a udf, and why that queries the same table, and why that query needs to be performed 8 times for every row in the table (or, more precisely every row where accCode<>''). If 48,000 rows match the criteria in that outer query, that's going to be 384,000 calls to the function, which is going to be a total 384,001 queries executed against the database.
I just can't fathom why you would need to do that, to get the specified resultset.
It would be much more efficient to get the information in just one pass through the table, with a query something like this:
SELECT accCode
, MAX(IF(vehichleManufacturer='HON','y','n')) AS purchasedHonda
, MAX(IF(vehichleManufacturer='YAM','y','n')) AS purchasedYamaha
, MAX(IF(vehichleManufacturer='KAW','y','n')) AS purchasedKawasaki
, ...
FROM _emarsys_vehiclessold
WHERE accCode<>''
GROUP
BY accCode
Your function includes a specification that the comparison should be done case insensitive collation. If you need to specify that, it can be done in the SQL
, MAX(IF(vehichleManufacturer='HON' COLLATE utf8_unicode_ci,'y','n'))
That query is likely to benefit from a covering index on accCode and vehichleManufacturer.
(That's an odd spelling in that vehichleManufacturer column name.)
The MySQL-specific IF() function could be replaced with an equivalent ANSI CASE expression, e.g.:
, MAX(CASE WHEN vehichleManufacturer='HON' THEN 'y' ELSE 'n' END)

Try:
SELECT accCode,
case sum(CASE accCode WHEN 'HON' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedHonda,
case sum(CASE accCode WHEN 'YAM' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedYamaha,
case sum(CASE accCode WHEN 'KAW' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedKawsaki,
case sum(CASE accCode WHEN 'SUZ' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedSuzuki,
case sum(CASE accCode WHEN 'DUC' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedDucati,
case sum(CASE accCode WHEN 'KTM' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedKTM,
case sum(CASE accCode WHEN 'SYM' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedSym,
case sum(CASE accCode WHEN 'VIC' THEN 1 ELSE 0 END)
when 0 then 'n' else 'y'
end purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>'' GROUP BY accCode

Many thanks to Steph for your help on this. To explain the data is being exported to a CSV file for external use and so the system it is being imported into needs a flat file only.
I have modified your query slightly and hey presto it works:
SELECT accCode,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='HON' THEN 1 ELSE 0 END)>0,'y','n')) purchasedHonda,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='KAW' THEN 1 ELSE 0 END)>0,'y','n')) purchasedKawasaki,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='SUZ' THEN 1 ELSE 0 END)>0,'y','n')) purchasedSuzuki,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='DUC' THEN 1 ELSE 0 END)>0,'y','n')) purchasedDucati,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='KTM' THEN 1 ELSE 0 END)>0,'y','n')) purchasedKTM,
(IF (SUM(CASE WHEN `vehichleManufacturer` ='SYM' THEN 1 ELSE 0 END)>0,'y','n')) purchasedSym,
(IF (SUM(CASE WHEN `vehichleManufacturer`='YAM' THEN 1 ELSE 0 END)>0,'y','n')) purchasedYamaha,
(IF (SUM(CASE WHEN `vehichleManufacturer`='VIC' THEN 1 ELSE 0 END)>0,'y','n')) purchasedVictory
FROM _emarsys_vehiclessold WHERE accCode<>''
GROUP BY accCode
Many thanks
Graham

Related

PHP SQL declare YES or NO based on count withing query

I am searching for a way to make the sql statement declare a AS example as Yes when the value is greater than 0 and No if 0 after I count the result while retreiving the data from the database.
This (is not working) is what I tried so far. I hope my tryout is making sence. I first make a select count on planning_clientid the result is 0 or more. If the result is 0 I need timesonplanning (perhaps change that name after its working) to be No and if higher than Yes. So in steady of the count result I need Yes or No, Is this possible?
Part that is not working:
(CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END AS timesonplanning
The whole statement:
SELECT a.*, own1.naam AS resposible_btw, own2.naam AS resposible_client, (CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END AS timesonplanning FROM tbl_clients a LEFT JOIN gebruikers own1 ON own1.id = a.client_ownerob LEFT JOIN gebruikers own2 ON own2.id = a.client_owner
Desired result:
timesonplanning Yes (when count if higher than 0)
timesonplanning No (when count is 0)
The error you indicated in the comments indicates a syntax error (albeit in Dutch). This is indeed to be expected as the query you included doesn’t close the initial parenthesis character ( you used right before your CASE keyword.
Resolve this by removing the initial parenthesis before CASE (as it doesn’t seem particularly necessary in this context), or properly close it by inserting a close parenthesis ) after the END keyword:
SELECT a.*, own1.naam AS resposible_btw, own2.naam AS resposible_client, (CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END) AS timesonplanning FROM tbl_clients a LEFT JOIN gebruikers own1 ON own1.id = a.client_ownerob LEFT JOIN gebruikers own2 ON own2.id = a.client_owner

CASE Statement MYSQL with Condition

I got 2 CASE statements: First CASE statement is as follows:
Case When ((cust_shipmentdate_awb Is Null OR cust_shipmentdate_awb = '')
AND (comp_shipdate_awb IS NULL OR comp_shipdate_awb = '')) Then 'Pending'
ELSE 'Shipped' End AS shipment_status
The Second CASE statement is as follows:
Case When apbg_bal_pay_amt ='0' Then 'Received'
Else 'Pending' End AS payment_status
Iam looking to write one more CASE statement named OVERALL_Status. That is basically a combination of both this CASES (shipment_status and payment_status), which means if Shipment status is 'Shipped' AND Payment_Status is 'Received' then Overall_status is 'Completed' else 'Not Completed'. Can anyone please help me on this. I am really struck here. I tried the combination of both the CASES, but not working:
Case When (cust_shipmentdate_awb Is Null OR cust_shipmentdate_awb = '') AND
(comp_shipdate_awb IS NULL OR comp_shipdate_awb = '') AND (apbg_bal_pay_amt != '0') Then
'Pending' ELSE 'Completed' End AS overall_status
There is two solutions as I see it:
1. You make the current query a subquery and add another CASE statement on the result of the subquery. (the pretty solution as I see it)
2. You add another WHEN to the existing case. Combining the clauses in the first two WHEN clauses to get the result. (probably the most optimized solution)
How about this?
(case when (cust_shipmentdate_awb Is Null OR cust_shipmentdate_awb = '') and
(comp_shipdate_awb IS NULL OR comp_shipdate_awb = '')
then 'Not Completed'
when apbg_bal_pay_amt = '0' Then 'Completed'
else 'Not Completed'
end) as overall_status

Select a 'virtual' column if another column has a value or is null in a SQL view

I want to select ALWAYS a column in my view, and set it with CASES.
example:
SELECT isDone
,doneN
from...
I have to set isDone in this way:
if done is 1 isDone is 'yes'
if done is 0 isDone is 'no'
(doneN is a column from another table, isDone instead doesn't exist in other tables, so it's a "virtual" column)
Thank you in advice
Is this what you want?
select (case when doneN = 1 then 'yes' else 'no' end) as isDoneN
. . .
You didn't specify whether 'done' will always be 0 or 1. If there are more values or you want to catch other values, use something like this:
select (case when done = 1 then 'yes'
when done = 0 then 'no'
else '' end) as isDone
, doneN
from ...
If the 'done' is constrained to be 0 or 1, you can use:
select (case when done = 1 then 'yes'
else 'np' end) as isDone
, doneN
from ...

Why query give not right results?

Good day.
Table have data:
id UserIdn CommentIdn LikeIdn NewsIdn Type IsFavorite DateCreate
1 527464 613895 748153 up yes 0000-00-00 00:00:00
For get count values i use code:
SELECT
count(Type='up') as CountUp,
count(Type='down') as CountDown
FROM Likes WHERE NewsIdn = '748153'
but in result instead
CountUp CountDown
1 0
i get
CountUp CountDown
1 1
Tell me please why i get not correct results? How query will be right?
Try using a case when in a sum().
SELECT SUM(CASE WHEN Type = 'up' THEN 1 ELSE 0 END) as 'count_up'
...
The Type='up' for example in your COUNT() function is either false (0) or true (1). But COUNT() doesn't care about that, it just sees that there is a row. Use SUM() instead:
SELECT
COALESCE(SUM(Type='up'), 0) as CountUp,
COALESCE(SUM(Type='down'), 0) as CountDown
FROM Likes WHERE NewsIdn = '748153'
Try this...
SELECT
SUM(CASE WHEN Type='up' AND Type IS NOT NULL THEN 1 ELSE 0 END) as CountUp,
SUM(CASE WHEN Type='down' AND Type IS NOT NULL THEN 1 ELSE 0 END) as CountDown
FROM Likes
WHERE NewsIdn = '748153'

using nested case condition in mysql query

if(qtype==3)
column=somecolumn;
else if(qtype==2)
{
if(open==0)
column=anycolumn;
else
column =somecolumn;
}
else{
acolumn,bcolumn,ccolumn //this else----|
} |
----------------|
I want to achieve the above nested if-else condition in my mysql query.where the condition will be based on one of the column.this is what i have done so far.
select qtype,open,(Case when qtype=2 then answer
Else (Case when qtype=3 then
(Case when open=0 then somecolumn
Else othercolumn End) End)
Else....//how to implement this else here)
i am in confusion how to integrate the last else part?
Thanks
The format is correct, but you switch the 2 and 3 compared to the if-else psuedocode at the begining:
select qtype,open,(Case when qtype=3 then answer
Else (Case when qtype=2 then
(Case when open=0 then somecolumn
Else othercolumn End) End))
Looking at the case syntax, here is what I came up with.
CASE qtype
WHEN 3 THEN column=somecolumn;
WHEN 2 THEN (CASE open WHEN 0 THEN column=anycolumn ELSE column = somecolumn)
ELSE othercolumn
END CASE