Concatenation is not working in select query - mysql

We are fetching list of ordered products from database including join with order table.
We want to list all orders with how many quantity of products order in each order on the basis of passed product ids. We also want to display customer name which was placed the order. So, as per our knowledge we have created an query to get items as:
SELECT
`main_table`.*,
`order`.*,
SUM(main_table.qty_ordered - main_table.qty_canceled) AS `custom_qty`,
SUM(main_table.row_total) AS `custom_row_total`,
SUM(main_table.tax_amount) AS `tax_amount`,
SUM(main_table.hidden_tax_amount) AS `hidden_tax_amount`,
SUM(main_table.discount_amount) AS `discount_amount`,
CONCAT(order.customer_firstname, ' ' ,order.customer_middlename, ' ', order.customer_lastname) AS full_name
FROM `sales_flat_order_item` AS `main_table`
INNER JOIN `sales_flat_order` AS `order` ON main_table.order_id=order.entity_id
WHERE (((((main_table.product_id = '902') OR (main_table.product_id = '903') OR (main_table.product_id = '904'))))) AND (main_table.store_id = '1') AND (CONCAT(order.customer_firstname, order.customer_middlename, order.customer_lastname) like '%rag%')
GROUP BY `main_table`.`sku`
All the aggregate functions used in above query working fine except concat(). Every time we will get the value of full_name column as NULL even we have name the corresponding concatenated columns.
Please any one helps me to figure out why this is not working. Are we doing something wrong in the above query?
Thanks in advance.

As CONCAT() returns NULL if any argument is NULL I'm guessing maybe one of the three arguments is NULL?
Try using the CONCAT_WS() function instead (as you use separators anyway) which skips null values.
CONCAT_WS(' ', order.customer_firstname, order.customer_middlename, order.customer_lastname) AS full_name
See the documentation for more information.
On a side note: you might want to look into how you can use table aliases to shorten the query text and make it more readable.

Are you sure EVERY column has an value? (Middlename?)
The MYSQL manual says:
SELECT CONCAT('My', NULL, 'QL')
-> NULL

Related

SQL query problem for getting the details under a individual date or date range from datetime

The sql query I have is :
Select count(cf_1519) as service_up,createdtime
from vtiger_ticketcf,vtiger_crmentity
Where date(createdtime)=date(now()) and
vtiger_ticketcf.cf_1519 like 'service up%' and
vtiger_crmentity.crmid = vtiger_ticketcf.ticketid"
which gives result as
again if i want to search the result individualyl by the query :
Select count(cf_1519) as service_up,createdtime
from vtiger_ticketcf,vtiger_crmentity
Where date(createdtime)= '16/10/2019%' and
vtiger_ticketcf.cf_1519 like 'service up%' and
vtiger_crmentity.crmid = vtiger_ticketcf.ticketid"
the result is not similar similar to previous :
I want to get the result by individual search by date only or a date range , i dont need the time
what changes in the sql code is needed to be done?
Your second query should look more like this:
select count(cf_1519) as service_up, max(createdtime)
from vtiger_ticketcf t join
vtiger_crmentity c
on c.crmid = t.ticketid
Where date(createdtime) = '2019-10-16' and
t.cf_1519 like 'service up%';
Notes:
You have an aggregation query (because of the count(), but have extraneous columns. All columns should be aggregated, except for those in the group by (and there are none).
Never use commas in the from clause. Always use proper, explicit, standard JOIN syntax.
You seem to want to use string functions on dates. I have never seen a date with a percentage sign in it.
Use proper date/time functions on date/time values, not string functions.

SQL Select Max of Columns Where Date is Not Null

I currently am using this query to select some data:
SELECT DISTINCT a.code AS code, name, max(scen.Is3D) AS Is3D FROM locations LEFT JOIN .... The scen table has columns Is3D and Date. I only want to select the max of items where the date IS NOT NULL. I tried max(scen.Is3D WHERE scen.Date IS NOT NULL), but that didn't work. I cannot change anything after the FROM in my query, so I need that filtering to be done in the MAX, if possible. I am using MySQL 5.7.
You can use:
MAX(CASE WHEN scen.date IS NOT NULL THEN scen.Is3D END) AS Is3D
The CASE expression returns NULL when none of the WHEN conditions is met, but MAX() ignores null values, so this will just return the max of the Is3D columns in the selected rows.
So if we can't change anything after the FROM, then we cannot get a perfect solution here. Since you are SELECTing out the NULL values. One thing that we can try if we can only modify the final output is this.
SELECT MAX(ISNULL(scen.Date,0))...
This will replace all the NULLs with 0, but it would help to know exactly what you are trying to do. Why are you so convinced that the query itself cannot be modified in any way?
The other solution would be to put the whole query in another wrapper.
That would look like:
SELECT *
FROM (
[your whole query here]
) AS inner
WHERE inner.Date IS NOT NULL

My SQL query not retrieving all the data from the database

I have a table in my database with the name contact. It has the following columns: name, mobile and twon. The problem is that I'm trying to get all the twon='Dubai', but when I execute my query it only retrieves 81000 rows but the total was 130000. The other remaining rows are not appearing in my query.
My Query:
SELECT * FROM `contact` WHERE `twon` = 'Dubai'
Can anyone tell me where I am going wrong or help me to access all the data from table?
= will fetch the record only if the column value is exactly 'dubai'.
Try with LIKE,TRIM and LOWER:
SELECT * FROM `contact` WHERE LOWER(TRIM(`twon`)) LIKE '%dubai%'
This query will fetch the records if twon column contains the word 'dubai'.
Different things could be wrong.
If you post examples of rows that should be returned, it would help us.
Case Sensitivity
If case sensitivity is a problem (e.g. 'dubai' or 'DUBAI' are not returned), you can use the LOWER function
SELECT * FROM `contact` WHERE LOWER(`twon`) = 'dubai'
Extra blanks
In some cases, extra blanks in the column content would fail, for instance ' Dubai' and ' Dubai '. You can use the TRIM function to get rid of trailing and leading blanks.
SELECT * FROM `contact` WHERE TRIM(`twon`) = 'Dubai'
Combination
Combining the two will work, too.
SELECT * FROM `contact` WHERE LOWER(TRIM(`twon`)) = 'dubai'

MySQL Dynamic HAVING Clause

I've written SELECT statement that works perfectly. However, I need to make some changes so that it now gets user submitted information from a form and returns results from the database based on that.
It will essentially be a product search—if a user searches for "red" they'll get back all items that are red. If they search for "red" and "wood" they'll get back only the items that are red and made of wood.
Here is my HAVING clause:
HAVING values LIKE "%Red%" AND values LIKE "%Wood%"
If I had a series of 5 drop down menus, each with a different set of terms, should I try to build the HAVING clause dynamically based on what drop downs the user uses? How would this be done?
I would opt for a static SQL statement, given that there are exactly five "options" the user can select from.
What I would do is use an empty string as the value that represents "no restriction" for a particular option, so my statement would be like this: e.g.
HAVING `values` LIKE CONCAT('%',:b1,'%')
AND `values` LIKE CONCAT('%',:b2,'%')
AND `values` LIKE CONCAT('%',:b3,'%')
AND `values` LIKE CONCAT('%',:b4,'%')
AND `values` LIKE CONCAT('%',:b5,'%')
To apply restrictions only on options 1 and 2, and no restriction on option 3, e.g.
$sth->bind_param(':b1','Red');
$sth->bind_param(':b2','Wood');
$sth->bind_param(':b3','');
$sth->bind_param(':b4','');
$sth->bind_param(':b5','');
To apply restriction only on option 2, e.g.
$sth->bind_param(':b1','');
$sth->bind_param(':b2','Wood');
$sth->bind_param(':b3','');
$sth->bind_param(':b4','');
$sth->bind_param(':b5','');
This allows you to have a static statement, and the only thing that needs to change is the values supplied for the bind parameters.
It's also possible to use a NULL value to represent "no restriction" for an option, but you'd need to modify the SQL statement to do a "no restriction" when a NULL value is supplied. Either check for the NULL value specifically, e.g.
HAVING ( `values` LIKE CONCAT('%',:b1,'%') OR :b1 IS NULL )
AND ( `values` LIKE CONCAT('%',:b2,'%') OR :b2 IS NULL )
AND ( `values` LIKE CONCAT('%',:b3,'%') OR :b3 IS NULL )
-or- just convert the NULL to an empty string for use in the LIKE predicate, e.g.
HAVING `values` LIKE CONCAT('%',IFNULL(:b1,''),'%')
AND `values` LIKE CONCAT('%',IFNULL(:b2,''),'%')
AND `values` LIKE CONCAT('%',IFNULL(:b3,''),'%')
The same technique will work with a WHERE clause as well. You may want to consider whether a WHERE clause is more appropriate in your case. (We can't tell from the information provided.)
But note that the HAVING clause does not restrict which rows are included in the statement; rather, the HAVING clause only restricts which rows from the result set are returned. The HAVING clause is applied nearly last in the execution plan (I think its followed only by the ORDER BY and LIMIT.
The HAVING clause can apply to aggregates, which the WHERE clause cannot do. The HAVING clause can reference columns in the SELECT list, which the WHERE clause cannot do.
(Also note that VALUES is a reserved word, if it's not qualified (preceded by alias., it may need to be enclosed in backticks.)
No, you should not build the HAVING clause.
Yes, you could build the WHERE clause as you suggested.
HAVING is used for imposing conditions involving aggregation functions on groups.
This approach make sense for where more conditions are involved, but you can use them on 5 as well. Collect your menu values into a temp table and then inner join them to your query on LIKE condition
SELECT .... FROM MyTable
INNER JOIN MyTempTable
ON values LIKE '%' + MenuValue '%'

I need some help getting MySql to output some results using a subquery

I'm storing a list of numbers inside a table as a varchar(255) and want to use this list in another query's "IN() clause.
Here's what I mean:
Table Data:
CREATE TABLE IF NOT EXISTS `session_data` (
`visible_portf_ids` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `session_data` (`visible_portf_ids`) VALUES
('45,44,658,659,661,45,44,658,659,661')
I want to run a query like this to return a list of portfolio's "QUERY #1":
SELECT portfolio_hierarchy_id, account_id, name, leaf_node_portf_id
FROM portfolio_hierarchy
WHERE account_id = 1
AND leaf_node_portf_id IN
(
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog')
)
ORDER BY name ASC
The result of the query above returns only 1 row, when there are a total of 3 that should have been returned.
If I run the subquery alone like this:
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog')
it will return a list like this:
45,44,658,659,661,45,44,658,659,661
But, when I run Query #1 above, only one row of data, which is associated with the "visible_portf_ids" of "45" is returned.
If I replace the subquery with hard coded values like this:
SELECT portfolio_hierarchy_id, account_id, name, leaf_node_portf_id
FROM portfolio_hierarchy
WHERE account_id = 1
AND leaf_node_portf_id IN (45,44,658,659,661,45,44,658,659,661)
ORDER BY name ASC
then I get all 3 rows I'm expecting.
I'm guessing that MySql is returning the list as a string because its stored as a varchar() and so it stops processing after the first "visible_portf_ids" is found, which is "45", but I'm not really sure.
Anyone got any ideas how I can fix this?
Thanks in advance.
You should think about restructuring your tables storing each value in a new row, instead of concatenating them.
Until then, you can use the FIND_IN_SET() function:
AND FIND_IN_SET(leaf_node_portf_id,
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog'
LIMIT 1)
) > 0
Unfortunately MySQL does not have a function to split a delimited string. Your IN argument is a single string with the result of your subquery. The reason it works when you hard-code it is that MySQL is parsing the values.
I suggest that you redesign your data base to store the visible ports list as separate rows in a separate table. Then you can retrieve them and use them in subqueries like you tried.