Concat reults when using case in statement - mysql

I've seen this question arise and seen it answered numerous times but not exactly they way in which I need. I have the following query
SELECT DISTINCT ia.UserName, ia.FirstName, ia.LastName, ia.`Password`,
CASE ipt.Code
WHEN ipt.Code LIKE "%CORP_FILE%" THEN "ROLE_GAAP"
WHEN ipt.Code LIKE "%RR_SUMMARY%" THEN "ROLE_RR"
END
AS "role"
FROM
iCTrunk.Account ia,
iCTrunk.AccountGroup ig,
iCTrunk.asscAccountAccountGroup iaaag,
iCTrunk.asscNodeAccountGroup ianag,
iCTrunk.asscNodeProjectType ianpt,
iCTrunk.ProjectType ipt
WHERE ia.Id = iaaag.AccountId
AND iaaag.AccountGroupId = ianag.AccountGroupId
AND ianag.NodeId = ianpt.NodeId
AND ianpt.ProjectTypeId = ipt.Id
AND ia.UserName = '<some user here>'
There are 2 possible result sets from the query and most users will only return 1. The issue is that if the user is an administrator then both query results will be returned. I am trying to figure out a way to group_concat the "role" field so that I only get a single returned row. Since the row result is being read by an authentication login page it would be much easier to process a single returned result.
Thank you in advance.

Just need to add the group_concat syntax and a group by; and I moved the distinct to be in the group_concat so you only get 0-2 results in the "Role" field.
SELECT ia.UserName, ia.FirstName, ia.LastName, ia.`Password`,
GROUP_CONCAT(DISTINCT CASE ipt.Code
WHEN ipt.Code LIKE "%CORP_FILE%" THEN "ROLE_GAAP"
WHEN ipt.Code LIKE "%RR_SUMMARY%" THEN "ROLE_RR"
END) AS "role"
FROM
iCTrunk.Account ia,
iCTrunk.AccountGroup ig,
iCTrunk.asscAccountAccountGroup iaaag,
iCTrunk.asscNodeAccountGroup ianag,
iCTrunk.asscNodeProjectType ianpt,
iCTrunk.ProjectType ipt
WHERE ia.Id = iaaag.AccountId
AND iaaag.AccountGroupId = ianag.AccountGroupId
AND ianag.NodeId = ianpt.NodeId
AND ianpt.ProjectTypeId = ipt.Id
AND ia.UserName = '<some user here>'
GROUP BY ia.UserName, ia.FirstName, ia.LastName, ia.`Password`
after the "END" in the case statement and before the ')' for group_concat, you could put...
ORDER BY ipt.code ASC SEPARATOR ',' if you want the names in a consistent order with a , separator. just wanted to make sure you understand the group_concat() syntax a bit more.

Related

MySQL: Get total number of customers and total of each status within a store [duplicate]

I have two tables, one is for news and the other one is for comments and I want to get the count of the comments whose status has been set as approved.
SELECT
ccc_news . *,
count(if(ccc_news_comments.id = 'approved', ccc_news_comments.id, 0)) AS comments
FROM
ccc_news
LEFT JOIN
ccc_news_comments
ON ccc_news_comments.news_id = ccc_news.news_id
WHERE
`ccc_news`.`category` = 'news_layer2'
AND `ccc_news`.`status` = 'Active'
GROUP BY
ccc_news.news_id
ORDER BY
ccc_news.set_order ASC
LIMIT 20
But the problem with this query is that the minimum value that is fetched for the comments column is 1 whether there is any comment existent corresponding to that news or not.
Any help would be highly appreciable.
Use sum() in place of count()
Try below:
SELECT
ccc_news . * ,
SUM(if(ccc_news_comments.id = 'approved', 1, 0)) AS comments
FROM
ccc_news
LEFT JOIN
ccc_news_comments
ON
ccc_news_comments.news_id = ccc_news.news_id
WHERE
`ccc_news`.`category` = 'news_layer2'
AND `ccc_news`.`status` = 'Active'
GROUP BY
ccc_news.news_id
ORDER BY
ccc_news.set_order ASC
LIMIT 20
Better still (or shorter anyway):
SUM(ccc_news_comments.id = 'approved')
This works since the Boolean type in MySQL is represented as INT 0 and 1, just like in C. (May not be portable across DB systems though.)
As for COALESCE() as mentioned in other answers, many language APIs automatically convert NULL to '' when fetching the value. For example with PHP's mysqli interface it would be safe to run your query without COALESCE().
This should work:
count(if(ccc_news_comments.id = 'approved', ccc_news_comments.id, NULL))
count() only check if the value exists or not. 0 is equivalent to an existent value, so it counts one more, while NULL is like a non-existent value, so is not counted.
Replace this line:
count(if(ccc_news_comments.id = 'approved', ccc_news_comments.id, 0)) AS comments
With this one:
coalesce(sum(ccc_news_comments.id = 'approved'), 0) comments
count(ccc_news_comments.id = 'approved' or null)
More concise

Using two sets of conditions in where clause

I'm trying to get the count of items in my table where it should satisfy these conditions
status = active
type = Pre-order
date = $date_input
OR
status = active
type = Both
date = $date_input
I'm trying to use this statement but I'm pretty sure it's messed up.
SELECT COUNT(id) as count_date from date_restriction
where (date='$date_input' AND status='active' AND type='Pre-order')
OR (date='$date_input' AND status='active' AND type='Both')
I also tried this to no avail
SELECT COUNT(id) as count_date from date_restriction
where date='$date_input' AND status='active' AND type='Pre-order' OR type='Both'
Whe you have mixed AND and OR condition you need () for the or clause
SELECT COUNT(id) as count_date
from date_restriction
where date='$date_input'
AND status='active'
AND ( type='Pre-order' OR type='Both')
or instear of several or condition you could use a IN clause
AND type IN ('Pre-order', 'Both')
anyway you should avoid the use of php var in SQL you are at risk for sqlinjection .. for avoid this you should take a look at prepared statement and binding param for your db driver
Your code should work. I would write this as:
select count(*) as count_date
from date_restriction
where date = ? AND status = 'active' AND
type in ('Pre-order', 'Both');
Note: The ? is for a parameter so you are not munging the query string with input values.
If I had to guess why this isn't working, I would speculate that one or both of the dates have a time component. You might try:
where date(date) = date(?) . . .
to be sure you are matching on the date, regardless of time.
SELECT count(id) as count_date
FROM date_restriction
WHERE date='$date_input' AND status='active' AND (type='Pre-order' OR type='Both');
Here, date and status both fields are common in your case; hence, don't wrap it in parenthesis whereas, add OR condition for type field only and con-cat it with AND in WHERE clause.

ORDER BY field when using table joins

I've got a products table that I'm trying to get to work. The query brings back results; however, it isn't actually using the ORDER BY FIELD to sort the results. It's skipping it somehow. I even tried ORDER BY FIELD(sc.id,'4','5','6'), and that didn't work either.
Is it even possible to use table_name.column in an ORDER BY FIELD()? Is there an alternative or a better method of doing this query?
$product = $db1q->query("
SELECT p.id, p.name, p.image, p.url,p.subcat as subcat, sc.id as scid,sc.name as scname
FROM Product as p
JOIN Product_Sub_Category as sc ON p.subcat = sc.id
WHERE p.visibility='1' AND find_in_set(p.id,'". $sidr['products'] ."')
ORDER BY FIELD(p.subcat,'4','5','6'), sc.sort_order ASC, p.sort_order ASC")
or die ('Unable to execute query. '. mysqli_error($db1q));
I just dumbed the query down to the basic level....
$product = $db1q->query("
SELECT id, name, image, url,subcat
FROM Product WHERE visibility='1' AND id IN ({$sidr['products']}) ORDER BY FIELD(subcat,'5','4','6','22')") or die ('Unable to execute query. '. mysqli_error($db1q));
and for some reason the order of my subcats are as follows....
3,12,23,5,5,4,4,4,4,4,22
Why wouldn't they begin with 5, 4, 6(doesn't exist), and 22? Then display 3,12, and 23 after those are first....
Simple Rextester Demo
When datatype is numeric don't compare to 'string' values
eg visibility = '1' if visibility is numeric you really shouldn't have the apostrophes around it. same in the field function given subcat.
$product = $db1q->query("SELECT id, name, image, url,subcat
FROM Product
WHERE visibility='1'
AND id IN ({$sidr['products']})
ORDER BY case when subcat in (5,4,6,22) then 0 else 1 end,
FIELD(subcat,5,4,6,22)
") or die ('Unable to execute query. '. mysqli_error($db1q));
or something like:
order by case when field(sort,'5','4','22') = 0 then (select max(sort)+1+sort from Product)
else field(sort,'5','4','22') end;
The issue with the 2nd approach is that it has to run a subquery for every record. In addition if the size of subcat/sort exceed or approach the max of int we'll run into a problem adding the values together. This problem is negated by using the 2 column sort approach in the first method.
Again, my gut feeling is that the first approach with 2 sort columns would be faster; and in my opinion easier to follow/maintain. The downfall is if the sort order defined changes then we have to change code. So... why have the order defined here... what isn't the order defined in a table; or is the order passed in as a parameter by user?

Multiplet select statements, each one uses CASE and return two values

i have the follwoing query:
SELECT COALESCE(income_adsense, income_adsense_u) AS "REV",
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS source
FROM revenue_report LIMIT 1;
which will return answer like this:
REV | source
376 | REAL
now the query works fine but the problem is i want to execute this select couple of times for different entity (adsense in the example).
the best i could get is this:
SELECT rr.site_id, ws.website_name,
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_taboola, income_taboola_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1
but the problem here is i'm missing the "REV" value from the upper example. I know it doesn't exists in the second query, but this is the last working attempt. any idea how can i add the "REV" value logic to the second query?
in the second query i will get this structure of result:
site_id|website_name|adsense_source|taboola_source
but here im missing the COALESCE result from the first query which in the example was 376
Well why can't you just include it in your SELECT list like
SELECT rr.site_id, ws.website_name,
COALESCE(income_adsense, income_adsense_u) AS "REV", //Here
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_gol, income_gol_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1

MySQL COUNT() causing empty array() return

MySQL Server Version: Server version: 4.1.14
MySQL client version: 3.23.49
Tables under discussion: ads_list and ads_cate.
Table Relationship: ads_cate has many ads_list.
Keyed by: ads_cate.id = ads_list.Category.
I am not sure what is going on here, but I am trying to use COUNT() in a simple agreggate query, and I get blank output.
Here is a simple example, this returns expected results:
$queryCats = "SELECT id, cateName FROM ads_cate ORDER BY cateName";
But if I modify it to add the COUNT() and the other query data I get no array return w/ print_r() (no results)?
$queryCats = "SELECT ads_cate.cateName, ads_list.COUNT(ads_cate.id),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName ORDER BY cateName";
Ultimately, I am trying to get a count of ad_list items in each category.
Is there a MySQL version conflict on what I am trying to do here?
NOTE: I spent some time breaking this down, item by item and the COUNT() seems to cause the array() to disappear. And the the JOIN seemed to do the same thing... It does not help I am developing this on a Yahoo server with no access to the php or mysql error settings.
I think your COUNT syntax is wrong. It should be:
COUNT(ads_cate.id)
or
COUNT(ads_list.id)
depending on what you are counting.
Count is an aggregate. means ever return result set at least one
here you be try count ads_list.id not null but that wrong. how say Myke Count(ads_cate.id) or Count(ads_list.id) is better approach
you have inner join ads_cate.id = ads_list.category so Count(ads_cate.id) or COUNT(ads_list.id) is not necessary just count(*)
now if you dont want null add having
only match
SELECT ads_cate.cateName, COUNT(*),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
having not count(*) is null
ORDER BY cateName
all
SELECT ads_cate.cateName, IFNULL(COUNT(*),0),
FROM ads_cate LEFT JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
ORDER BY cateName
Did you try:
$queryCats = "SELECT ads_cate.cateName, COUNT(ads_cate.id)
FROM ads_cate
JOIN ads_list ON ads_cate.id = ads_list.category
GROUP BY ads_cate.cateName";
I am guessing that you need the category to be in the list, in that case the query here should work. Try it without the ORDER BY first.
You were probably getting errors. Check your server logs.
Also, see what happens when you try this:
SELECT COUNT(*), category
FROM ads_list
GROUP BY category
Your array is empty or disappear because your query has errors:
there should be no comma before the FROM
the "ads_list." prefix before COUNT is incorrect
Please try running that query directly in MySQL and you'll see the errors. Or try echoing the output using mysql_error().
Now, some other points related to your query:
there is no need to do ORDER BY because GROUP BY by default sorts on the grouped column
you are doing a count on the wrong column that will always give you 1
Perhaps you are trying to retrieve the count of ads_list per ads_cate? This might be your query then:
SELECT `ads_cate`.`cateName`, COUNT(`ads_list`.`category`) `cnt_ads_list`
FROM `ads_cate`
INNER JOIN `ads_list` ON `ads_cate`.`id` = `ads_list`.`category`
GROUP BY `cateName`;
Hope it helps?