Coalesce not working in insert statement for a null table - mysql

I am trying to use the coalesce function in SQL to avoid getting an error when inserting a row with an auto-incrementing uid into a table that is null. However, the following code is still giving me:
"cannot insert the value null into column 'TABLE_ONE_UID'".
cmdEx.ExecuteNonQuery(
"INSERT INTO TABLE_ONE
(TABLE_ONE_UID, USER_UID, SHT_DATE,
C_S_UID, CST_DATE,
CET_DATE, S_M, PGS)
VALUES ((SELECT MAX(COALESCE(TABLE_ONE_UID, 0)) + 1
FROM TABLE_ONE),
127, '2009-06-15T13:45:30',
0, '2009-06-15T13:45:30','2010-06-15T13:45:30',
'TEST DELETE THIS ROW', 0 )");

The correct way to solve this is with an auto_increment column:
create table PMS_CALC_SCHEDULE (
PMS_CALC_SCHEDULE_UID int auto_increment primary key,
. . .
);
If, for some reason, you want to do the calculation yourself, subject your code to race conditions, and have slower inserts, then you need to do the coalesce in the right place:
INSERT INTO PMS_CALC_SCHEDULE (PMS_CALC_SCHEDULE_UID, . . .)
SELECT COALESCE(MAX(PMS_CALC_SCHEDULE_UID), 0) + 1,
. . .
FROM PMS_CALC_SCHEDULE ;

This would happen when your source table doesn't have any row, MAX would return null in this case.
To prevent this, you can use interchange COALESCE and MAX, e.g.:
INSERT INTO PMS_CALC_SCHEDULE
(PMS_CALC_SCHEDULE_UID, USER_UID, SCHEDULED_DATE,
PMS_CALC_STATUS_UID, CALCULATION_START_DATE,
CALCULATION_END_DATE, STATUS_MESSAGE, PROGRESS)
VALUES ((SELECT COALESCE(MAX(PMS_CALC_SCHEDULE_UID), 0) + 1
FROM PMS_CALC_SCHEDULE),
127, '2009-06-15T13:45:30',
0, '2009-06-15T13:45:30','2010-06-15T13:45:30',
'TEST DELETE THIS ROW', 0 )")
Here's the SQL Fiddle.

If the field is set to AutoIncrement on the table itself, just leave the field out of your Insert-Statement. The value is added by the database itself.

Related

SQL IF exist date by day do increment update else insert data

How can I express the below statement as a SQL query ?
IF EXISTS (SELECT * FROM expense_history
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date , '%Y-%m-%d') = '2018-06-02'
AND camp_id='80')
UPDATE expense_history
SET clicks = clicks + 1,
amount = amount + 1
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date, '%Y-%m-%d') = '2018-06-02'
AND camp_id = '80'
ELSE
INSERT INTO expense_history (camp_id, created_date, amount, user_id)
VALUES ('80', '2018-06-02 12:12:12', '1', '40')
END IF;
I just want to do increment clicks and amount if is set by day, else I want to add new row.
This is very tricky in MySQL. You are storing a datetime but you want the date part to be unique.
Starting in MySQL 5.7.?, you can use computed columns for the unique constraint. Here is an example:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime datetime, -- note I changed the name
created_date date generated always as (date(created_datetime)),
unique (user_id, camp_id, created_datetime)
);
You can then do the work as:
INSERT INTO expense_history (camp_id, created_datetime, amount, user_id)
VALUES (80, '2018-06-02 12:12:12', 1, 40)
ON DUPLICATE KEY UPDATE
amount = COALESCE(amount + 1, 1),
clicks = COALESCE(clicks + 1, 1);
Earlier versions of MySQL don't support generated columns. Nor do they support functions on unique. But you can use a trick on a prefix index on a varchar to do what you want:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime varchar(19),
unique (created_datetime(10))
);
This has the same effect.
Another alternative is to store the date and the time in separate columns.
I presumed your database is mysql, because of DATE_FORMAT() function(and edited your question as to be).
So, by using such a mechanism below, you can do what you want,
provided that a COMPOSITE PRIMARY KEY for camp_id, amount, user_id columns :
SET #camp_id = 80,
#amount = 1,
#user_id = 40,
#created_date = sysdate();
INSERT INTO expense_history(camp_id,created_date,amount,user_id,clicks)
VALUES(#camp_id,#created_date,#amount,#user_id,ifnull(clicks,1))
ON DUPLICATE KEY UPDATE
amount = #amount + 1,
clicks = ifnull(clicks,0)+1;
SQL Fiddle Demo

SSRS 2008 R2 - all parameters multi value AND optional

I've got a report that has 6 parameters. All parameters need to be optional and 3 have to be multi-value. One of the optional parameters is a dropdown, the rest are manually keyed in text boxes.
The Where clause below works when there are multiple #VendorNum values and one #FullJA value, but fails with multiple #FullJA values regardless of the #VendorNum count.
Parameters:
#VendorNum - keyed manually by user (space delimited) - optional, can be multivalue
#FullJA - keyed manually by user (space delimited) - optional, can be multivalue
#BU - optional, can be multivalue - when #JA is populated, this will auto-populate, if #JA isn't populated it's a dropdown with all selected.
#JA3 - keyed by user - optional, single value
#StartDate and #EndDate - optional single values
select * from some_table
WHERE
/*FULL JA*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEFT(JA, 7) IN (#FullJA)
AND BU IN(#BU)
AND #JA3 IS NULL
)
OR
/*DATE RANGE*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEN(ISNULL(CONVERT(VARCHAR(20), Cleared_When), '0')) >= #ClearedOnly
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND BU IN (#BU)
AND #FullJA IS NULL
AND #JA3 IS NULL
)
/*BUS UNIT AND JA3*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND LEFT(JA, 3) = (#JA3)
AND #FullJA IS NULL
)
/*BUS UNIT ONLY*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND #JA3 IS NULL
AND #FullJA IS NULL
)
The dataset parameter values for #FullJA and #VendorNum are both
=IIF(InStr(Parameters!FullJA.Value," ")>0,SPLIT(Parameters!FullJA.Value," "),Parameters!FullJA.Value) and all params are set as NOT multivalue, with nulls allowed.
Any help would be greatly appreciated. I've written over 200 reports for this project and this is the only one that is really grinding my gears!
Thanks!
I would approach this by building up some temp tables / table variables, to hold the potentially multi-valued variables, and then joining to those tables. This has the advantage of you being able to insert all possible values, in the case they have omitted the variable. So, you'd split your strings and put them into those tables (something along the lines of this example) if given the variable, and otherwise just do an insert into to populate your temp table / table variable.
For a split function, I prefer something like this:
create FUNCTION [dbo].[Split] (#sep VARCHAR(32), #s VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
SELECT r.value('.','VARCHAR(MAX)') as Item
FROM (SELECT CONVERT(XML, N'<root><r>' + REPLACE(REPLACE(REPLACE(#s,'& ','& '),'<','<'), #sep, '</r><r>') + '</r></root>') as valxml) x
CROSS APPLY x.valxml.nodes('//root/r') AS RECORDS(r)
)
GO
GRANT SELECT
ON OBJECT::[dbo].[Split] TO PUBLIC
AS [dbo];
I would then put those variables into a table using something like this (my separator is a ", "):
select ltrim(rtrim(ppl.Item)) as PersonName
into #gppl
from dbo.Split(', ', #PersonListForCompare) as ppl
You would do something more like:
select ltrim(rtrim(vnd.Item)) as VendorNum
into #vendorNums
from dbo.Split(', ', #VendorNum) as vnd
You would then join to that temp table just like any other table & use it to limit your results that way. In your case, you want to put in all vendors (possibly) if they didn't give you any input. So, you'd do something like:
create table #vendorNums (VendorName varchar(64)) --I have no idea, here, what this data looks like
if #VendorNum is not null and datalength(#VendorNum) > 0
insert into into #vendorNums (VendorNum)
select ltrim(rtrim(vnd.Item))
from dbo.Split(', ', #VendorNum) as vnd
else
insert into into #vendorNums (VendorNum)
select VendorNum
from dbo.Vendors
That said, I think that you could use your select from dbo.Split directly as a table in a join, rather than putting it into the temp table. Only problem would be you'd have to be sure you had data in there to split, or else you're going to have a bunch of combinations to get the right match-up of null parameters vs. filled ones.

Mysql and between\in range condition

We have x2 columns min and max. Each can be null or integer. When we start search throw table we cannot use BETWEEN command... Question is, how to find in range with this conditions
value is greater then min (if it's not null)
and
value is less then max (if it's not null)
and
value is in range of min and max (if they BOTH not null)
value - our integer number. As you can see we cannot use BETWEEN command.
So NULL means no limit. You can still use BETWEEN:
select *
from mytable
where #value between coalesce(minvalue, #value) and coalesce(maxvalue, #value);
Or simply AND:
select *
from mytable
where #value >= coalesce(minvalue, #value)
and #value <= coalesce(maxvalue, #value);
Or the very basic AND and OR:
select *
from mytable
where (#value >= minvalue or minvalue is null)
and (#value <= maxvalue or maxvalue is null);
Use this:
WHERE col BETWEEN COALESCE(min, -2147483648) AND COALESCE(max, 2147483647)
According to your logic, if either the min or max be NULL, then the restriction should be ignored. In the above WHERE clause, if min be NULL then col will always be greater than the lower boundary, assuming that col is an integer. Similar logic applies to the max condition.
The large (and small) numbers you see represent the largest and smallest possible values for an integer in MySQL.
Without the option of using BETWEEN, I would recommend using a simple WHERE-AND clause.
If null values are not allowed, you should use the COALESCE function
http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce
Returns the first non-NULL value in the list, or NULL if there are no non-NULL values.
SELECT *
FROM SCORES
WHERE score >= COALESCE(min_score, score)
AND score <= COALESCE(max_score, score)
Here is a sample fiddle I created
http://sqlfiddle.com/#!9/306947/2/0
My solution Yii2 AR like
$query
->joinWith(['vacancySalary'])
->andWhere([
'and',
'IF (vacancy_salary.min IS NULL, ' . $this->salaryMin . ', vacancy_salary.min) >= ' . $this->salaryMin,
'IF (vacancy_salary.max IS NULL, ' . $this->salaryMin . ', vacancy_salary.max) <= ' . $this->salaryMin
]);
Simple answer is use IF condition and proper values.
ADDED:
Another way to go
$query
->joinWith(['vacancySalary'])
->andWhere($this->salaryMin . ' BETWEEN IF(vacancy_salary.min IS NULL, 0, vacancy_salary.min) AND IF(vacancy_salary.max IS NULL, 0, vacancy_salary.max)');

INSERT INTO with subquery & parameters not working in MS-Access

I have an INSERT INTO which works fine with the parameters as constants:
INSERT INTO FinalValidityCodes
(tblReceivedSamplersID, Substudy, Location, FinalValidityCode, DateTimeProcessed)
SELECT ID, true, 'I', 0, now()
FROM tblReceivedSamplers
WHERE (SampleID = ?)
This would affect 1 row (as expected)
Yet if I change the query to use parameters it will allow it to run but will never affect any rows.
INSERT INTO FinalValidityCodes
(tblReceivedSamplersID, Substudy, Location, FinalValidityCode, DateTimeProcessed)
SELECT ID, ?, ?, ?, ?
FROM tblReceivedSamplers
WHERE (SampleID = ?)
What is the difference and why, when I use parameters, does the Insert, seemingly, fail?
Edit:
SampleID is a text datatype.
It looks like the purpose of that INSERT is to add a single row to FinalValidityCodes with values for 5 fields. However, 4 of those values will be supplied directly by query parameters, and ID/tblReceivedSamplersID will be derived from another parameter.
So I would try a DLookup() expression to get the ID (using the parameter for SampleID), and insert that value along with the other 4 parameter values. Here is an untested guess.
INSERT INTO FinalValidityCodes (
tblReceivedSamplersID,
Substudy,
Location,
FinalValidityCode,
DateTimeProcessed
)
VALUES (
DLookup("ID", "tblReceivedSamplers", "SampleID ='" & param1 & "'"),
param2,
param3,
param4,
param5
);

MySql: updating a column with the column's content plus something else

I'm don't have a lot of knowledge of MySql (or SQL in general) so sorry for the noobness.
I'm trying to update a bunch of String entries this way:
Lets say we have this:
commands.firm.pm.Stuff
Well I want to convert that into:
commands.firm.pm.print.Stuff
Meaning, Add the .print after pm, before "Stuff" (where Stuff can be any Alphanumerical String).
How would I do this with a MySql Query? I'm sure REGEXP has to be used, but I'm not sure how to go about it.
Thanks
Try something like this. It finds the last period and inserts your string there:
select insert(s, length(s) - instr(reverse(s), '.') + 1, 0, '.print')
from (
select 'commands.firm.pm.Stuff' as s
) a
To update:
update MyTable
set MyColumn = insert(MyColumn, length(MyColumn) - instr(reverse(MyColumn), '.') + 1, 0, '.print')
where MyColumn like 'commands.firm.pm.%'
Perhaps use a str_replace to replace commands.firm.pm to commands.firm.pm.print
$original_str = "commands.firm.pm.15hhkl15k0fak1";
str_replace("commands.firm.pm", "commands.firm.pm.print", $original_str);
should output: commands.firm.pm.print.15hhkl15k0fak1
then update your table with the new value...How to do it all in one query (get column value and do the update), I do not know. All I can think of is you getting the column value in one query, doing the replacement above, and then updating the column with the new value in a second query.
To update rows that end in '.Stuff' only:
UPDATE TableX
SET Column = CONCAT( LEFT( CHAR_LENGTH(Column) - CHAR_LENGTH('.Stuff') )
, '.print'
, '.Stuff'
)
WHERE Column LIKE '%.Stuff'
To update all rows - by appending .print just before the last dot .:
UPDATE TableX
SET Column = CONCAT( LEFT( CHAR_LENGTH(Column)
- CHAR_LENGTH(SUBSTRING_INDEX(Column, '.', -1))
)
, 'print.'
, SUBSTRING_INDEX(Column, '.', -1)
)
WHERE Column LIKE '%.%'