MySQL: handling conditional values within GROUP_CONCAT - mysql

I'm trying retrieve data using a LEFT JOIN and GROUP_CONCAT(). However, where values aren't present, I need something to represent the lack of data, or a method of identification for each, so that I can do something with them in the application.
CONCAT_WS(0x1D,
GROUP_CONCAT(DISTINCT bcod1.value
SEPARATOR 0x1F),
GROUP_CONCAT(DISTINCT bcod2.value
SEPARATOR 0x1F),
GROUP_CONCAT(DISTINCT bcod3.value
SEPARATOR 0x1F),
GROUP_CONCAT(DISTINCT bcod4.value
SEPARATOR 0x1F)) AS clients_options
Here, the four instances of GROUP_CONCAT() relate to either an INNER JOIN or a LEFT JOIN in a search performed by the user:
INNER JOIN
bookings_clients_options bco1 ON (bco1.client_id = '3')
INNER JOIN
bookings_clients_options_data bcod1 ON (bco1.name = 'unit_code')
AND (bco1.bookings_client_option_id = bcod1.bookings_client_option_id)
AND (bcod1.value REGEXP ('.*'))
AND (bcod1.booking_attendee_id = bookings_attendees.booking_attendee_id)
INNER JOIN
bookings_clients_options bco2 ON (bco2.client_id = '3')
INNER JOIN
bookings_clients_options_data bcod2 ON (bco2.name = 'creditor_ev_number')
AND (bco2.bookings_client_option_id = bcod2.bookings_client_option_id)
AND (bcod2.value REGEXP ('.*'))
AND (bcod2.booking_attendee_id = bookings_attendees.booking_attendee_id)
INNER JOIN
bookings_clients_options bco3 ON (bco3.client_id = '3')
LEFT JOIN
bookings_clients_options_data bcod3 ON (bco3.name = 'purchase_order_number')
AND (bco3.bookings_client_option_id = bcod3.bookings_client_option_id)
AND (bcod3.booking_attendee_id = bookings_attendees.booking_attendee_id)
INNER JOIN
bookings_clients_options bco4 ON (bco4.client_id = '3')
INNER JOIN
bookings_clients_options_data bcod4 ON (bco4.name = 'purchase_order_booking')
AND (bco4.bookings_client_option_id = bcod4.bookings_client_option_id)
AND (bcod4.value REGEXP ('Y'))
AND (bcod4.booking_attendee_id = bookings_attendees.booking_attendee_id)
Here, bcod3.value is where the results "collapse" in that if there's no value for bcod3.value but a value for bcod4.value, then bcod4.value drops into the space for bcod3.value.
As you can see, each of these columns has a name, but having tried...
GROUP_CONCAT(DISTINCT bcod" . $x . ".value SEPARATOR 0x1F) AS unit_code
... I got an error from the surrounding CONCAT_WS().
I tried...
IF(bcod" . $x . ".value = '', 'QQQ', GROUP_CONCAT(DISTINCT bcod" . $x . ".value SEPARATOR 0x1F))
... but that doesn't appear to do anything.
I tried...
GROUP_CONCAT(DISTINCT IF(bcod" . $x . ".value = 0, 'QQQ', bcod" . $x . ".value) SEPARATOR 0x1F)
.. and while it did grab the instances of bcod3.value, it also grabbed some of the instances of bcod1.value that have values which are not '0'.

I'm not 100% sure I understand your question, but I think I do. Sample data and desired results are worth 1000 words of explanation.
If the problem is that NULL or blank values are being ignored, then just do:
CONCAT_WS(0x1D,
coalesce(GROUP_CONCAT(DISTINCT bcod1.value SEPARATOR 0x1F), ''),
coalesce(GROUP_CONCAT(DISTINCT bcod2.value SEPARATOR 0x1F), ''),
coalesce(GROUP_CONCAT(DISTINCT bcod3.value SEPARATOR 0x1F), ''),
coalesce(GROUP_CONCAT(DISTINCT bcod4.value SEPARATOR 0x1F), '')
) AS clients_options
It is generally considered a benefit that group_concat() and concat_ws() ignore NULL values. However, if you want to do something with them, just use coalesce().

Related

COUNT and GROUP_CONCAT in mysql

I am having three tables pcn_type, in_e_s_s__p_c_ns, p_c_n_details. I am trying to concat three different values into single using group concat.
My Query:
SELECT 'browser' AS NAME, CONCAT( '[', CONCAT('{"', pcn_type.name, '",',
COUNT(JPN_ID), '}'), ']' ) AS DATA FROM p_c_n_details INNER JOIN
in_e_s_s__p_c_ns RIGHT OUTER JOIN pcn_type ON pcn_type.name =
p_c_n_details.type AND in_e_s_s__p_c_ns.pcnid=
p_c_n_details.JPN_ID GROUP BY pcn_type.name
Result got:
NAME | DATA
-------------------------------------
browser [{"Design Change",4}]
browser [{"EOL",10}]
browser [{"Process Change",21}]
Expecting Result:
NAME | DATA
--------------------------------------------------------------------
browser [{"Design Change",4},{"EOL",10},{"Process Change",21}]
How to restructure the above query to get the expected result.
use GROUP_CONCAT function
select name,GROUP_CONCAT(DATA SEPARATOR ' ')
from
(
SELECT 'browser' AS NAME, CONCAT( '[', CONCAT('{"', pcn_type.name, '",',
COUNT(JPN_ID), '}'), ']' ) AS DATA FROM p_c_n_details INNER JOIN
in_e_s_s__p_c_ns RIGHT OUTER JOIN pcn_type ON pcn_type.name =
p_c_n_details.type AND in_e_s_s__p_c_ns.pcnid=
p_c_n_details.JPN_ID GROUP BY pcn_type.name
) as T group by name

Mysql Concat is displaying byte array

I am new at mysql. I have code but it is displaying byte array why ?
Sorry about my english :(
SELECT p.city_id,p.name city, CONCAT("[",
GROUP_CONCAT(CONCAT('{id:"', a.id, '", address:"', a.address, '"}')),
"]") As sahalar
FROM cities AS p LEFT JOIN carpet_fields As a ON(p.city_id = a.city_id)
GROUP BY p.city_id, p.name ORDER BY p.city_id
it must be show json data but. The result is
Wrong result
city_id name sahalar
1 ADANA 0x5B7B69643A223236222C20616464726573733A2248757A75
Correct result
city_id name sahalar
1 ADANA [{id:"1A", address:"Huzurevleri Mah.77232 Sk. ADANA / ÇUKUROVA"},{id:"1B", address:"KARSLILAR MAH. 82008. SOK. / MAHFESIGMAZ"}]
I found the solution
SET SESSION group_concat_max_len = 1000000;
SELECT p.city_id,p.name city,
CONCAT("[",
GROUP_CONCAT( CONCAT('{id:"', CAST(a.id as char(10)), '", address:"', a.address, '"}') ),
"]") As sahalar
FROM cities AS p
LEFT JOIN carpet_fields As a ON(p.city_id = a.city_id)
GROUP BY p.city_id, p.name ORDER BY p.city_id

MySQL: Return only if all values in IN() match a result

Solution
Query
SELECT a.introtext FROM ( SELECT b.content_item_id as id,COUNT(DISTINCT b.tag_id) as rc FROM `#__contentitem_tag_map` AS `b` INNER JOIN `#__tags` AS `c` ON (`b`.`tag_id` = `c`.`id`) WHERE `c`.`alias` IN ("") GROUP BY `b`.`content_item_id`)f INNER JOIN `#__content` AS `a` ON (`a`.`id` = `f`.`id`) INNER JOIN `#__contentitem_tag_map` AS `b` ON (`a`.`id` = `b`.`content_item_id`) INNER JOIN `#__tags` AS `c` ON (`b`.`tag_id` = `c`.`id`) WHERE `c`.`alias` IN ("") AND `a`.`state` = 1 AND `c`.`level` > 0 AND `c`.`published` = 1 AND `a`.`catid` = 27 AND `f`.`rc` = 1 GROUP BY `a`.`id` ORDER BY a.title ASC
Joomla SQL
This is the Joomla SQL inside a custom module
// Create a new query object.
$subQuery = $db->getQuery(true);
$query = $db->getQuery(true);
$tags = array('facebook','html5');
$count = count($tags);
$tags = '"' . implode('","',$tags) . '"';
$subQuery
->select(array('b.content_item_id as id','COUNT(DISTINCT b.tag_id) as rc'))
->from($db->quoteName('#__contentitem_tag_map','b'))
->join('INNER', $db->quoteName('#__tags', 'c') . ' ON (' . $db->quoteName('b.tag_id') . ' = ' . $db->quoteName('c.id') . ')')
->where(($db->quoteName('c.alias') . ' IN ('.$tags.')'))
->group($db->quoteName('b.content_item_id'));
$query
->select(array('a.introtext'))
->from('('.$subQuery.')f')
->join('INNER', $db->quoteName('#__content', 'a') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('f.id') . ')')
->join('INNER', $db->quoteName('#__contentitem_tag_map', 'b') . ' ON (' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.content_item_id') . ')')
->join('INNER', $db->quoteName('#__tags', 'c') . ' ON (' . $db->quoteName('b.tag_id') . ' = ' . $db->quoteName('c.id') . ')')
->where(($db->quoteName('c.alias') . ' IN ('.$tags.')'), 'AND')
->where(($db->quoteName('f.rc') . ' = ' . $count))
->group($db->quoteName('a.id'))
->order('a.title ASC');
I am using MySQL and the contents of Joomla! 3.8 database.
Tables in use
#__content
#__contentitem_tag_map
#__tags
The Story
I created articles with profiles of Developers. Each Developer can tag him/herself with skills like "jQuery", "html5", etc.
Those skills are stored as tags in the #__tags table.
I try to select all developers from the #content table that match the tags I am searching for.
For example I am looking for a dev, who can do 'HTML5' as well as 'JavaScript'.
The results should be empty, because there is a single dev for 'HTML5' & 'CSS3' and another dev for 'CSS3' only in my database.
The ugly truth
Searching for 'HTML5' and 'Javascript' returns 1 result.
The way it should be
Searching for 'HTML5' and 'Javascript' should return 0 results because there is no Dev with both skills.
The Query
SELECT
a.id as id,
a.title,
c.id as tag_id,
c.alias as tag_alias
FROM `#__content` as `a`
INNER JOIN `#__contentitem_tag_map` AS b ON (a.id = b.content_item_id)
INNER JOIN `#__tags` AS c ON (b.tag_id = c.id)
WHERE c.alias IN ('html5','javascript')
id | title | tag_id | tag_alias
-------------------------------
22 | xyz | 6 | html5
The Question
What to do? By the way I cannot use stuff like HAVING COUNT(\*) = x; because there will be multiple results with multiple tags.
Thank you for your support! <3
Additional Information
Using HAVING COUNT(\*) = x (where x is the amount of tags used) returns only 1 Developer/Tag and not every Developer with this specific tag.
SQL Fiddle
http://sqlfiddle.com/#!9/f5cb6f/2
I tried to find a solution for your question (I am not sure query can not be better; I don't like very much that I have to repeat two times condition c.alias IN ('html5','javascript') ).
Perhaps it's not important for you, but this query can be used on other db engine too other than Mysql (eg. MSSQL) as it doesn't use GROUP_CONCAT or "permissive" GROUP BY clause.
The query seems to work for more values other than two (eg. three alias to check), changing condition for RC too of course.
In the inner part, it counts the (distinct) value for each tag present in table #__contentitem_tag_map: so in the outer part the query can extract tags having at least two (or the number desired, specified in WHERE condition RC=xx) values present. This permits to "simulate" the sort of "AND condition" you needed. In the outer part query makes other necessary joins to extract columns desired.
(In the inner part, as you can see, it's not necessary to use table #__content).
I added following data to your sample data:
INSERT INTO `#__content` (`id`, `title`) VALUES (29, 'New one');
INSERT INTO `#__contentitem_tag_map` (`content_item_id`, `tag_id`) VALUES (29, 6);
INSERT INTO `#__contentitem_tag_map` (`content_item_id`, `tag_id`) VALUES (29, 1);
INSERT INTO `#__tags` (`id`, `alias`) VALUES (1,'facebook');
SELECT F.ID,
A.title as title,
B.tag_id,
C.alias as tag_alias
FROM (SELECT b.content_item_id as id,
COUNT(DISTINCT b.tag_id) AS RC
FROM `#__contentitem_tag_map` AS b
INNER JOIN `#__tags` AS c ON b.tag_id = c.id
WHERE c.alias IN ('html5','facebook')
GROUP BY b.content_item_id
) F
INNER JOIN `#__content` A ON A.id = F.id
INNER JOIN `#__contentitem_tag_map` B ON a.id = B.content_item_id
INNER JOIN `#__tags` C ON B.tag_id = C.id
WHERE C.alias IN ('html5','facebook')
AND F.RC=2;
;
Output:
ID title tag_id tag_alias
1 29 New one 6 html5
2 29 New one 1 facebook

Multiple WHERE clauses with a condition

I've looked at a bunch of similar stackoverflow questions but I haven't been able to figure this out.
WHERE `Table1`.`Column1` = 'criteria1'
AND `Table1`.`Column2` = 'criteria2'
AND `Table1`.`Column3` LIKE 'criteria3'
AND IF(EXISTS IN `Table2`, (`Table2`.`Delete` <> 2, `Table2`.`SectionId` IS NOT NULL), '')
I'm trying to execute a query with five WHERE clauses, where the last two are based on the condition that the row exists in the joined Table2. If the condition is false, throw in an empty string ''.
I've tried variations of the above code but it's incorrect syntax. Is what I'm trying to do possible?
Can I use an IF inside a WHERE clause like that?
EDIT (here's the full query...):
$sql_query = "SELECT
`Courses`.`Id` AS CourseId,
IFNULL(`Courses`.`CourseName`, '') AS CourseName,
IF(`Courses`.`CourseNumber` > '', `Courses`.`CourseNumber`, -1) AS CourseNumber,
IFNULL(`Courses`.`CourseDepartment`, '') AS CourseDepartment,
IFNULL(`Courses`.`Notes`, '') AS CourseNotes,
IFNULL(`Courses`.`Year`, '') AS CourseYear,
IFNULL(`Courses`.`CourseType`, '') AS CourseType,
`Sections`.`Id` AS SectionId,
IFNULL(`Sections`.`SectionNumber`, '') AS SectionNumber,
IFNULL(`Sections`.`SectionName`, '') AS SectionName,
`StudentsCourses`.`CustomerId` AS CustomerId,
CONCAT(`Courses`.`Id`, '-', `Sections`.`Id`, '-', `StudentsCourses`.`FirstName`, `StudentsCourses`.`LastName`, '_', `StudentsCourses`.`TeacherEmail`) AS TempCustomerId,
IFNULL(`StudentsCourses`.`FirstName`, '') AS StudentFirstName,
IFNULL(`StudentsCourses`.`LastName`, '') AS StudentLastName,
IFNULL(`Customers`.`Email`, IFNULL(`StudentsCourses`.`StudentEmail`, '')) AS StudentEmail,
IFNULL(`StudentsCourses`.`TeacherFirstName`, '') AS TeacherFirstName,
IFNULL(`StudentsCourses`.`TeacherLastName`, '') AS TeacherLastName,
IF(`StudentsCourses`.`CustomerId` IS NOT NULL, `Customers`.`CustomerName`, CONCAT(`StudentsCourses`.`FirstName`, ' ', `StudentsCourses`.`LastName`)) AS FullName,
IF(`StudentsCourses`.`CustomerId` IS NOT NULL, CONCAT(REPLACE(`Customers`.`CustomerName`, ' ', ''), '_', `Customers`.`Email`), CONCAT(`StudentsCourses`.`FirstName`, `StudentsCourses`.`LastName`, '_', `StudentsCourses`.`TeacherEmail`)) AS NameKey,
`Customers`.`UserRoleId` AS UserRoleId,
`Customers`.`MagentoId` AS MagentoId,
`StudentsCourses`.`StudentId` AS StudentId,
`SiteProfile`.`StudentIdField` AS StudentIdField,
`SiteProfile`.`SchoolEmailDomain` AS SchoolEmailDomain,
`StudentsCourses`.`Id` AS StudentsCoursesId,
IFNULL(`Orders`.`Id`, '') AS OrderId
FROM `Courses`
LEFT JOIN `StudentsCourses` ON `Courses`.`Id` = `StudentsCourses`.`CourseId`
LEFT JOIN `BooksCourses` ON `Courses`.`Id` = `BooksCourses`.`CourseId`
LEFT JOIN `Products` ON `BooksCourses`.`ISBN` = `Products`.`ISBN`
LEFT JOIN `EbookVendors` ON `Products`.`EbookVendorId` = `EbookVendors`.`Id`
LEFT JOIN `Sections` ON `Sections`.`Id` = `StudentsCourses`.`SectionId`
LEFT JOIN `Customers` ON `StudentsCourses`.`CustomerId` = `Customers`.`Id`
LEFT JOIN `SiteProfile` ON `Courses`.`SchoolCode` = `SiteProfile`.`SchoolCode`
LEFT JOIN `Orders` ON `Customers`.`Id` = `Orders`.`CustomerId`
WHERE `Courses`.`SchoolCode` = '{$criteria["school_code"]}'
AND `Courses`.`Year` = {$criteria["year"]}
AND `Courses`.`CourseType` LIKE '{$criteria["term"]}'
AND `StudentsCourses`.`Delete` <> 2
AND `StudentsCourses`.`SectionId` IS NOT NULL";
It is not very clear exactly what you are asking, but I am guessing something like this condition might be what you are looking for:
AND (StudentCourses.CourseId IS NULL
OR (`StudentsCourses`.`Delete` <> 2
AND `StudentsCourses`.`SectionId` IS NOT NULL
)
)
Edit: It would best if you edited your question to explain in plain language what you want the condition to do, as it is not apparent at all what the intent was from the syntax you originally presented.

group_concat missing on of the group

I have two tables, the first puts puts pairs of people into a group with fldPairNum and a second table which collects scores for each individual person.
The problem I have is that if only one of the pair has submitted a score, then only their name appears in the 'nameOfPair' column, but I really need both names. What can I do to fix this?
SELECT
group_concat(DISTINCT `delegate`.`fldFirstName`,' ',`delegate`.`fldSurname` SEPARATOR ' and ') AS 'nameOfPair',
Sum(`data`.`fldScore`) AS 'totalScore'
FROM
`data`
Inner Join `delegate` ON `data`.`fldDelegateID` = `delegate`.`fldID`
WHERE
`delegate`.`fldCategory` > '0'
AND
`delegate`.`fldPairNum` > '0'
GROUP BY
`delegate`.`fldPairNum`
Many thanks
Dave
SELECT GROUP_CONCAT(DISTINCT
`delegate`.`fldFirstName`, ' ', `delegate`.`fldSurname`
SEPARATOR
' and ') AS 'nameOfPair',
SUM(`data`.`fldScore`) AS 'totalScore'
FROM `delegate`
LEFT JOIN `data`
ON `data`.`fldDelegateID` = `delegate`.`fldID`
WHERE `delegate`.`fldCategory` > '0'
AND `delegate`.`fldPairNum` > '0'
GROUP BY `delegate`.`fldPairNum`