Sequelize returns different value than MySql result - mysql

I have something very odd happening and nothing seems to work. I have a SP in MySql that returns some results. When I run the SP in MySql workbench everything is correct. The query is quite long. But this is the LEFT JOIN is somehow creating the issues. I have other inner joins/left joins but they are fine.
SELECT DISTINCT Id.ReelTag
, Id.ECSPartNo
, WM.ShortDescription AS Description
, Id.ReelTagSerial
, group_concat(DISTINCT RA.UniqueID) AS UniqueID
, group_concat(DISTINCT coalesce(RA.OrdNo, Std.OrdNo)) AS OrdNo
, Id.Received
, IFNULL(Std.ReelQuantity,0) AS OriginalQuantity
, IFNULL(Id.Quantity,0) AS CurrentQuantity
, IFNULL(yest.Quantity,0) AS YesterdayQuantity
, IFNULL(cuts.Quantity,0) AS QuantityChanged
, cuts.OrdNo AS OrdNoChange
, IFNULL(CC.ShipQuantity,0) AS ShipQuantity
, CC.OrdNo AS OrdNo_Allocated
, IFNULL(Id.Quantity,0) - IFNULL(yest.Quantity,0) AS changeAOF_Yesterday
FROM InventoryDtl Id .....
LEFT JOIN (
SELECT
SourceReel
, SUM(CASE WHEN Action = 'Insert' THEN TotalQuantity
WHEN Action = 'Delete' THEN -TotalQuantity
ELSE 0 END) AS Quantity
, group_concat(DISTINCT CASE WHEN Action = 'Insert' THEN concat(OrdNo,'(Cut)') ELSE concat(OrdNo,'(UnCut)') END) AS OrdNo
FROM (
SELECT
Action
, SourceReel
, OrdNo
, SUM(Quantity) AS TotalQuantity
FROM CableCuts_Log CD
WHERE 1=1
AND 1 = CASE
WHEN SourceReel IS NOT NULL AND OrdNo LIKE 'E9%' AND Quantity > 0 AND DaTediff(Now(),LogDate) = 0 THEN 1
ELSE 0 END
GROUP BY Action, SourceReel, OrdNo
) CC
WHERE 1=1
GROUP BY SourceReel
) cuts ON Id.ReelTag = cuts.SourceReel
Again, When I run this in MySql workbench it's fine and loads in a second if that makes a difference.
But when I call my API to call the SP using ...
let inventoryReport = await models.sequelize
.query(
`call rpt_DailyInventoryReport($location, $byECSPartNo);`,
{ bind: {location: req.body.location, byECSPartNo: null} },
)
for(i=0;i<inventoryReport.length;i++) {
if(inventoryReport[i].ReelTagSerial == '6906' || inventoryReport[i].ReelTagSerial == '6858') {
console.log(inventoryReport[i]);
}
}
and exporting that into an Excel using ExcelJS, the 2 "cuts" columns from the query are essentially NULLs, because the return value of the "cuts" select are coming up NULLS, which is why it's giving the IFNULL value instead. Again this work in MySql workbench.
These are the values the API throws out.
{
"ReelTagSerial": 6858,
"CurrentQuantity": 700,
"YesterdayQuantity": 2500,
"QuantityChanged": 0,
"OrdNoChange": null,
"ShipQuantity": 0,
"OrdNo_Allocated": null,
"changeAOF_Yesterday": -1800
},
{
"ReelTagSerial": 6906,
"CurrentQuantity": 2730,
"YesterdayQuantity": 3330,
"QuantityChanged": 0,
"OrdNoChange": null,
"ShipQuantity": 0,
"OrdNo_Allocated": null,
"changeAOF_Yesterday": -600
},
Here are the 2 rows that their values should be.
{
"ReelTagSerial": 6906,
"CurrentQuantity": 2730,
"YesterdayQuantity": 3330,
"QuantityChanged": 600,
"OrdNoChange": E92021(Cut),
"ShipQuantity": 0,
"OrdNo_Allocated": null,
"changeAOF_Yesterday": -600
}
{
"ReelTagSerial": 6858,
"CurrentQuantity": 700,
"YesterdayQuantity": 2500,
"QuantityChanged": 1800,
"OrdNoChange": E912345(Cut),
"ShipQuantity": 0,
"OrdNo_Allocated": null,
"changeAOF_Yesterday": -1800
},
I have tried creating a temp table and defining the field type of varchar, text, mediumint for the QuantityChanged field.
At first I thought maybe ExcelJs was not liking the key/value pairs but then I simply console logged the 2 rows and they are returning like that from Sequelize. I have tried casting the 2 fields with every datatype possible.
, CAST(cuts.OrdNo AS char) AS OrdNoChange
, CAST(cuts.OrdNo AS binary) AS OrdNoChange
Now I am just immediately sending the return result as a response back to Postman and seeing all the rows to make sure for whatever reason those values are not being set in other rows. But they seem to be all good.
If I simply rearrange the columns so that the two bad fields get values of other fields, they do populate with their values, so that's about as far as I got. Or if I put just 1000 or a string type it returns correctly, so IT MUST be something to do with those 2 data types from the "cuts" query.
I have tried returning simply returning these from the "cuts" join query
SELECT
DISTINCT SourceReel
#, CAST(SUM(CASE WHEN Action = 'Insert' THEN TotalQuantity
# WHEN Action = 'Delete' THEN -TotalQuantity
# ELSE 0 END) AS UnSigned) AS Quantity
, SUM(TotalQuantity) AS Quantity
, OrdNo
#, group_concat(DISTINCT CASE WHEN Action = 'Insert' THEN concat(OrdNo,'(Cut)') ELSE concat(OrdNo,'(UnCut)') END) AS OrdNo
Nothing is working. Spent hours troubleshooting and searching...
Need some help please :)
Thanks in advance.

I was able to get around this by creating a table and inserting into it during the SP call. Then in NodeJs I created a model of that table and just used to find everything in the table immediately after I called the SP.
let inventoryReport = await models.Rpt_DailyInventory_Temp.findAll();
Then just TRUNCATE the table every time the SP is called.

Related

How to implement where condition only if we are passing values in MySQL

This is what I'm calling and passing from service:
List<String> projectOwners = filterComponent.getProjectOwner();
List<String> dataProviderCodes = filterComponent.getDataProvider();
custEnrollmentMgmts = customerEnrollmentManagementRepository.findActiveByPage(getArchiveDate(),
completedEnrollmentStatusCodes, projectOwners, dataProviderCodes, getNoSearchCriteria(projectOwners, dataProviderCodes), pageRequest);
This is the query:
select distinct a.*
from cust_enrollment_mgmt a
inner join cust_enrollment_rel_mgmt r
on a.cust_enrollment_proj_id=r.cust_enrollment_proj_id
left join cust_prime p
on p.cust_prime_id = r.cust_prime_id
where a.cust_enrollment_proj_id NOT IN
(
select ce.cust_enrollment_proj_id
from cust_enrollment_mgmt ce
inner join enrollment_status_avt es
on ce.enrollment_status_id = es.enrollment_status_id
where ce.sys_update_ts < "2022-06-06 00:00:00"
and es.enrollment_status_desc in ("Complete", "Inactive")
)
and
(
if ((:code) is not null and (:name) is not null ,
a.data_provider_cd in (:code) and p.cust_prime_nm in (:name),0)
or
if ((:code) is not null and (:name) is null , a.data_provider_cd in (:code),0)
or
if ((:code) is null and (:name) is not null , p.cust_prime_nm in (:name),0)
or 1=:nosearchcriteria
);
If and only if the dataProviderCodes or projectOwners is not empty
then only it should go to that where condition.
If I pass dataProviderCodes and pass projectOwners then it should
fetch only projectOwner data If I'm not passing anything then it has
to stop ("Complete", "Inactive") and fetch up to that.
After that ("Complete", "Inactive") I need to fetch as per this
condition ☝☝☝.
The main thing is that it has to fetch only if data is present for the param we are passing.
This is working but if I pass more than 1 data It fails because I'm passing a list it may contain 1 or more than 1 or empty. For example: for dataProviderCodes if I pass ["aa","bb"] it fails.
I need to perform fetching if and only if the values are not null or present.
The whole implementation is regarding filtering.

MySQL JSON_EXTRACT subquery not working when enclosed in IFNULL

Goal
Select a value based on a value returned by a subquery that is using JSON_EXTRACT which either returns a 'value' or NULL. IFNULL should be able to allow you to set a default value when the JSON_EXTRACT does not return a result.
Problem
When using a subquery that uses JSON_EXTRACT and returns a result, will return nothing when enclosed in IFNULL ignoring the default value.
Consider the following case
We want to select a SubscriptionPlan.name based on an identifier that is the result of a subquery using JSON_EXTRACT.
SELECT
subscriptionplan.name
FROM
SubscriptionPlan AS subscriptionplan
WHERE
subscriptionplan.identifier = (
SELECT
JSON_EXTRACT(product.data, '$.identifier')
FROM
Subscription AS subscription
JOIN
Product AS product ON product.productid = subscription.productid
WHERE
subscription.status = 'ACTIVE'
AND
subscription.ownerid = :userId
)
Case 1. SUCCESS without IFNULL
Subscription exists with status 'ACTIVE' and 'userId'
- Subquery result: 'PRO' and thus finds the SubscriptionPlan
- Final result: 'Professional'
Case 2. NOT FOUND without IFNULL
Subscription not found with status 'ACTIVE' and 'userId'
- Subquery result: NULL and thus does not find a SubscriptionPlan
- Final result: NULL
Now we add the IFNULL operation to default to 'FREE' subscription plan:
subscriptionplan.identifier = IFNULL(
( SELECT JSON_EXTRACT ... ),
'FREE'
)
Case 3. SUCCESS with IFNULL
Subscription exists with status 'ACTIVE' and 'userId'
- Subquery result: NULL even though the subscription was found !???
- Final result: NULL
Case 4. NOT FOUND with IFNULL
Subscription not found with status 'ACTIVE' and 'userId'
- Subquery result: FREE and thus finds the FREE SubscriptionPlan
- Final result: 'Free'
The IFNULL expression nullifies the subquery result, and it does not default to 'FREE'.
My thoughts are as follows:
Case 4: is using the IFNULL default value string 'FREE' and therefore works as intended
Case 3: subquery should return PRO and even if it returns NULL, it should default to 'FREE', neither happens
Maybe adding the IFNULL query adds another nesting layer where
What i've tried and did not work:
IF( () IS NULL, 'do stuff', 'do other stuff')
IF( ISNULL(<query<), 'do stuff', 'do other stuff')
IF( () = null , ..., ...)
IF( () = NULL , ..., ...)
IF( () = 'null' , ..., ...)
IF( () = 'NULL' , ..., ...)
Also according to Can't detect null value from JSON_EXTRACT:
IF ( JSON_EXTRACT(product.data, '$.identifier') = CAST('null' AS JSON), ...., ... )
All failures! Why is JSON_EXTRACT subquery not working when enclosed in IFNULL?
I've found out what caused the error.
JSON_EXTRACT adds quotes around its result resulting in "PRO" instead of PRO and therefore the IFNULL default is not triggered and the subscription plan, which is PRO, is not found using "PRO".
Add JSON_UNQUOTE around the JSON_EXTRACT solves the issue.

Transfer null sql query result to a string

I'm writing a query to get gross profit percentage "GP%" of a certain product to put it in a C# grid view by product by year. I Want the query result to be dynamic that in some years this product was n't sold so the result will be (profit/sales)=(0/0) it will be null. this null isn't accepted by C#.
The query is
SELECT
FORMAT((SELECT ((ISNULL(SUM([Profit]), NULL)) / ISNULL(SUM([Sales]), NULL))
FROM [dbo].[Sales]
WHERE [ProdHeir01_2] = 'Batteries'
AND [Sales_Year] = 2015
AND [Month_Number] BETWEEN 1 AND 8, 'P') AS [Percentage]
This query results in 'Null'. How can I insert a condition to transfer null to a string value. so the query to be dynamic :).
Thanks a lot in advance......
Regards
Here is on technique you may find helpful:
select 0 / CASE WHEN IsNull([Sales],0) = 0 THEN 1 ELSE [Sales] END
Hady, here you go.
--CTE(Common Table Expression) with your query
WITH preselect AS
(
SELECT
FORMAT(
(SELECT ISNULL(SUM([Profit]), NULL) / ISNULL(SUM([Sales]), NULL)
FROM [dbo].[Sales]
WHERE [ProdHeir01_2] = 'Batteries'
AND [Sales_Year] = 2015
AND [Month_Number] BETWEEN 1 AND 8
)
,'P'
) AS [Percentage])
--Case statement that will return Null as string when Null and the percentage
--when it isn't null
SELECT CASE WHEN [Percentage] IS NULL THEN 'Null' ELSE [Percentage] END AS [Percentage]
FROM preselect

MySQL Left Join, SELECT a field either from one or the other if null

I am trying to LEFT JOIN 2 tables. which is working out fine. But i am getting back two sets of fields named setting_value. iam trying to get tblSettings.setting_value only if tblAgencySettings.setting_value is NULL. How would i go about doing this? I know i can rename the fields, then in PHP i can check the tblAgencySettings.setting_value and if NULL then grab the tblSettings.setting_value but i prefer to keep this at MySQL.
SELECT `tblSettings`.`id`, `tblSettings`.`setting_name`,
`tblSettings`.`setting_value`, `tblAgencySettings`.`setting_value`
FROM `tblSettings` LEFT JOIN `tblAgencySettings`
ON `tblSettings`.`id` = `tblAgencySettings`.`setting_id`
AND `tblAgencySettings`.`agency_id` = '1'
WHERE `tblSettings`.`changeable` = '1'
slight issue i just noticed. i failed to mention this. if tblAgencySettings.setting_value does have a value. but changeable is not 1 then just select tblSettings.setting_value
Just add a COALESCE:
SELECT `tblSettings`.`id`, `tblSettings`.`setting_name`,
COALESCE(`tblAgencySettings`.`setting_value`, `tblSettings`.`setting_value`)
FROM `tblSettings` LEFT JOIN `tblAgencySettings`
ON `tblSettings`.`id` = `tblAgencySettings`.`setting_id`
AND `tblAgencySettings`.`agency_id` = '1'
WHERE `tblSettings`.`changeable` = '1'
The COALESCE function returns the first non-NULL value you give it so this:
COALESCE(`tblAgencySettings`.`setting_value`, `tblSettings`.`setting_value`)
Will be tblAgencySettings.setting_value if that's not NULL and tblSettings.setting_value if tblAgencySettings.setting_value is NULL.
If tblAgencySettings.setting_value can also be zero and you want to ignore that as well as NULL, then you could use this instead of the COALESCE above:
COALESCE(
IF(`tblAgencySettings`.`setting_value` = 0, NULL, `tblAgencySettings`.`setting_value`),
`tblSettings`.`setting_value`
)
The IF returns the second argument if the first is true and the third if the first argument is false so the above use converts zero to NULL. Or, you could go all the way to a CASE statement:
case
when `tblAgencySettings`.`setting_value` = 0 then `tblSettings`.`setting_value`
when `tblAgencySettings`.`setting_value` IS NULL then `tblSettings`.`setting_value`
else `tblSettings`.`setting_value`
end
Change your SQL Statement to this:
SELECT `tblSettings`.`id`, `tblSettings`.`setting_name`,
CASE WHEN `tblSettings`.`setting_value` IS NULL THEN `tblAgencySettings`.`setting_value`
ELSE `tblSettings`.`setting_value` END AS `setting_value`
FROM `tblSettings` LEFT JOIN `tblAgencySettings`
ON `tblSettings`.`id` = `tblAgencySettings`.`setting_id`
AND `tblAgencySettings`.`agency_id` = '1'
WHERE `tblSettings`.`changeable` = '1'
Here's a link to MYSQL CASE Statement for your reference.

MySQL CASE "Else Case When" is executing when the precondition is true - what am I missing?

I have a table that, due to the third party system we are using, sometimes has duplicate data. Since the model uses an EAV method there's no way to filter this the "right" way, so I am aggregating the data into a View - I know this is a data collection problem but it's easier for me to fix it on the display end than go through this system and potentially break existing data and forms. I need to check one of two fields to see if one or both are entered, but only pick one (otherwise the name displays twice like this: "John,John" instead of just "John"). Here's my code for the relevant part:
group_concat(
(
case when (`s`.`fieldid` = 2) then `s`.`data`
else
case when (`s`.`fieldid` = 35) then `s`.`data`
else NULL end
end
) separator ','),_utf8'') as first_name
If both fieldid 2 and fieldid 35 are entered, I would expect this to just return the value from fieldid = 2 and not the value from fieldid = 35, since the Else clause shouldn't execute when the original case when is true. However it's grabbing that, and then still executing the case when inside of the else clause?
How can I fix this code to give me either fieldid = 2 OR fieldid = 35, but avoid globbing them both together which results in the name being duplicated?
EDIT
Here is the table structure:
table: subscribers_data
subscriberid (int) fieldid (int) data (text)
It uses an E-A-V structure so a sample record might be:
subscriberid fieldid data
1 2 John
1 3 Smith
1 35 John
1 36 Smith
with fieldid 2 and 35 being the custom field "First Name" (defined in a separate table) and fieldid 3 and 36 being "Last Name".
Here is the full view that I'm using:
select `ls`.`subscriberid` AS `id`,
left(`l`.`name`,(locate(_utf8'_',`l`.`name`) - 1)) AS `user_id`,
ifnull(group_concat((
case when (`s`.`fieldid` = 2) then `s`.`data`
when (`s`.`fieldid` = 35) then `s`.`data`
else NULL end) separator ','),_utf8'') AS `first_name`,
ifnull(group_concat((
case when (`s`.`fieldid` = 3) then `s`.`data`
when (`s`.`fieldid` = 36) then `s`.`data`
else NULL end) separator ','),_utf8'') AS `last_name`,
ifnull(`ls`.`emailaddress`,_utf8'') AS `email_address`,
ifnull(group_concat((
case when (`s`.`fieldid` = 81) then `s`.`data`
else NULL end) separator ','),_utf8'') AS `mobile_phone`,
ifnull(group_concat((
case when (`s`.`fieldid` = 100) then `s`.`data`
else NULL end) separator ','),_utf8'') AS `sms_only`
from ((`list_subscribers` `ls`
join `lists` `l` on((`ls`.`listid` = `l`.`listid`)))
left join `subscribers_data` `s` on((`ls`.`subscriberid` = `s`.`subscriberid`)))
where (left(`l`.`name`,(locate(_utf8'_',`l`.`name`) - 1)) regexp _utf8'[[:digit:]]+')
group by `ls`.`subscriberid`,`l`.`name`,`ls`.`emailaddress`
The view is being used as the Model for a Ruby on Rails application, so I'm using some creative hacking to fake out a "user_id" that Rails expects (we name the field list.name in the Lists table using a numeric ID that our front-end Rails app generates when we add a new user, so I'm extracting just this number to make the view look like a Rails-convention database table)
I am not a mysql guy, but in a sql server case statement, you could do it without the first 'else'
case
when fieldid = 2 then data
when fieldid = 35 then data
else null
end
Also, you seem to be returning the same 'data' field in both cases
Anything inside group_concat() doesn't have a way to see the context in which it's running. So, you have have two rows in a single group, one with fieldid=2 and second with fieldid=35, it will do the following:
processing row with fieldid=2...
s.fieldid = 2 is true, return s.data
processing row with fieldid=35...
s.fieldid = 2 is false, try the else part
s.fieldid = 35 is true, return s.data
This explains why is "John" returned multiple times. The only way to fix it is to run a different query outside of group_concat().
EDIT:
Ih you really have to do it this way, use something like this instead:
SELECT ...
min(CASE WHEN s.fieldid IN (2,35) THEN s.data ELSE NULL END) AS first_name
...
Alternatively you can do group_concat(DISTINCT ...) if the two values can't be different (otherwise you would get e.g. "John,Johny"). Why do you have two values for first_name/last_name though?