I am trying to cast some bad data into proper data using CAST(column AS DECIMAL(7,2)), which works when just SELECTing, but once combined with an INSERT statement, the statement fails:
/* setup */
drop table if exists dst;
create table dst (
id int not null auto_increment
, columnA decimal(7,2)
, primary key (id)
);
drop table if exists src;
create table src (
id int not null auto_increment
, columnA varchar(255)
, primary key (id)
);
insert into src (columnA) values ('');
/* test */
/* This works as I would like it to*/
select CAST(columnA AS decimal(7,2)) from src; /* returns 0.00 */
/* This fails */
insert into dst (columnA)
select CAST(columnA AS decimal(7,2)) from src;
/*0 19 21:01:56 insert into dst (columnA)
select cast(columnA as decimal(7,2)) from src Error Code: 1366. Incorrect decimal value: '' for column '' at row -1 0.000 sec*/
Edit: this is a pared down reproduction example - the data I am
working with is much more varied than just an empty string - it might
also be a non-numeric string value or a numeric value that is outside
of the bounds of decimal(7,2) - in which the CAST statement works
the way I would like it to when only in a SELECT but fails when
trying to use them as part of the INSERT.
Am I doing something wrong, or is there another way to achieve what I am looking for?
I am using MYSQL 5.6.11 on WIN 7 x64
Set explicitly the value for the empty string with CASE or IF:
SELECT CASE WHEN columnA = '' THEN 0 ELSE CAST(columnA AS decimal(7,2)) END
FROM src;
SELECT IF(columnA <> '', CAST(columnA AS decimal(7,2)), 0)
FROM src;
Or use 2 SELECTs with UNION ALL :
SELECT CAST(columnA AS decimal(7,2))
FROM src
WHERE columnA <> ''
UNION ALL
SELECT 0
FROM src
WHERE columnA = '';
You can try using REGEXP to filter out any irregularities in source data:
INSERT INTO dst (columnA)
SELECT CAST(CASE
WHEN columnA REGEXP '^[0-9]{0,7}(\.[0-9]{0,2})$' THEN columnA
ELSE 0
END AS decimal(7,2))
FROM src;
SQL Fiddle Demo here
Related
I have to sort an alphanumeric value containing some special characters in sql server, I have tried several order by clause but it is not giving the desired output( It is giving the output as 1,10,100 than 101 it should be 1,2,3..100 )
I have tried ordering by alphabets and number at same time by split but it didn't worked.
Here my solution. The first, I create a function that gets number from the string. And then sort this number.
USE tempdb
GO
CREATE TABLE MyTable (ID INT, Col1 VARCHAR(100))
GO
-----
INSERT INTO MyTable (ID, Col1)
SELECT 1, 'CBSFBE20151202000017_000_1.tif'
UNION ALL
SELECT 2, 'CBSFBE20151202000017_000_10.tif'
UNION ALL
SELECT 3, 'CBSFBE20151202000017_000_2.tif'
UNION ALL
SELECT 4, 'CBSFBE20151202000017_000_3.tif'
UNION ALL
SELECT 5, 'CBSFBE20151202000017_000_11.tif'
-----
CREATE FUNCTION dbo.fnGetNumberFromString (#strInput VARCHAR(255))
RETURNS VARCHAR(255)
AS
BEGIN
DECLARE #intNumber int
SET #intNumber = PATINDEX('%[^0-9]%', #strInput)
WHILE #intNumber > 0
BEGIN
SET #strInput = STUFF(#strInput, #intNumber, 1, '')
SET #intNumber = PATINDEX('%[^0-9]%', #strInput)
END
RETURN ISNULL(#strInput,0)
END
GO
-----
SELECT *, dbo.fnGetNumberFromString(Col1) AS Number
FROM MyTable
order by CAST(dbo.fnGetNumberFromString(Col1) AS float), Col1
Trying to do something very simple.
Want to Run a SP that checks if one of the arguments is null. If so, store an empty string in a log table, otherwise store the value.
CREATE DEFINER=`root`#`localhost` PROCEDURE `SP_TestVariable`(
Code1 varchar(255) ,
CodeToTest varchar(255)
)
BEGIN
CASE
WHEN CodeToTest IS NULL THEN
set #FinalCode = ' '
ELSE
set #FinalCode = CodeToTest
end
-- Now do the insert into the log table
INSERT INTO `TempLogTable` ( strField1, strField2)
VALUES (Code1 , #FinalCode );
You can reduce all that to a simle query
INSERT INTO `TempLogTable` (strField1, strField2)
SELECT Code1, coalesce(CodeToTest, '')
and for that I would even drop the procedure and just use the query instead.
I have created a function to encapsulate a select on PL/SQL.
But the result I get from using the function is different that the one I get from using the select on it's own.
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(fermentacion IN VARCHAR2)
RETURN DATE
IS fecha DATE;
BEGIN
SELECT (
SELECT fecha
FROM (
SELECT t.id, t.fecha
FROM TrasiegoAux t
WHERE t.fermentacion=fermentacion
ORDER BY t.fecha desc
)
WHERE ROWNUM=1
) INTO fecha FROM DUAL;
RETURN(fecha);
END;
Is there something wrong on the declaration of my function? Right now it always returns the same value no matter what parameter it gets as input.
The expected output is the date of the last Trasiego (the max date of the table).
This is my structure:
CREATE TABLE Fermentacion(
id VARCHAR2(36)
);
CREATE TABLE Trasiego(
id VARCHAR2(36),
fecha DATE not null,
fermentacion VARCHAR2(36) REFERENCES Fermentacion,
temperatura NUMBER(8) not null,
litrosFinal NUMBER(8) not null,
PRIMARY KEY(id, fermentacion)
);
create or replace view TrasiegoAux as select id, fecha, fermentacion from Trasiego;
Here is some data:
Insert into FERMENTACION (ID) values ('4');
Insert into FERMENTACION (ID) values ('9');
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,FECHA) values ('1','4',20,190,to_date('04-OCT-16','DD-MON-RR'));
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,EMPLEADOLABORATORIO,FECHA) values ('2','4',20,180,to_date('11-OCT-16','DD-MON-RR'));
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,FECHA) values ('3','9',20,190,to_date('04-OCT-16','DD-MON-RR'));
Given that data I would expect that this:
DECLARE
fecha date;
BEGIN
fecha :=fecha_ultimo_trasiego(4);
DBMS_OUTPUT.PUT_LINE(fecha); //'11-OCT-16'
fecha :=fecha_ultimo_trasiego(4);
DBMS_OUTPUT.PUT_LINE(fecha); //'04-OCT-16'
END;
It's most likely to be because you're passing in the parameter with the same name as the column. That's not a good idea, as it causes all sorts of strangeness.
You can either amend the parameter name, e.g.:
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(p_fermentacion IN VARCHAR2)
...
WHERE t.fermentacion = p_fermentacion
...
or you could qualify the parameter name in the query:
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(fermentacion IN VARCHAR2)
...
WHERE t.fermentacion = fecha_ultimo_trasiego.fermentacion
...
You need to give the parameter a different name to any of the columns in TrasiegoAux, or else prefix it with the function name, e.g.
WHERE t.fermentacion = fecha_ultimo_trasiego.fermentacion
or else (after renaming the parameter):
WHERE t.fermentacion = p_fermentacion
Edit: Boneist beat me to it.
You could probably simplify the code a bit, though, as the select ... from dual wrapper doesn't seem to be needed:
create or replace function fecha_ultimo_trasiego
( p_fermentacion in trasiegoaux.fermentacion%type )
return date
as
l_fecha date;
begin
select fecha into l_fecha
from ( select t.fecha
from trasiegoaux t
where t.fermentacion = p_fermentacion
order by t.fecha desc )
where rownum = 1;
return l_fecha;
end;
0 72 17:37:20 call new_procedure Error Code: 1292. Truncated incorrect
INTEGER value: '_3_ELECTRICITY BILL_3.pdf' 0.140 sec
note: 3_ELECTRICITY BILL_3.pdf value contains in tbl_AccountOpeningForm table in AttachmentName column
but if i removed having clause from query it work fine.
tbl_AccountOpeningForm
CustNo VARCHAR(80)
AttachmentName VARCHAR(100)
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `new_procedure`()
BEGIN
drop table if exists tblReport;
create temporary table tblReport
(
CustNo varchar(80)
) ;
insert into tblReport (CustNo)
select CustNo
from tbl_AccountOpeningForm
group by CustNo
having COUNT(case when LTRIM(RTRIM(AttachmentName))='' then null else AttachmentName end)!=
COUNT(case when LTRIM(RTRIM(AttachmentName))!='' then null else AttachmentName end) limit 10000000;
select * from tblReport;
END
Try phrasing the logic like this:
having SUM(LTRIM(RTRIM(AttachmentName)) <> '') <> SUM(LTRIM(RTRIM(AttachmentName)) = '')
limit 10000000;
MySQL is usually pretty smart about the return type from a case expression. The error message suggests that it is getting confused. If this is the problem, then the simplified logic should fix it.
Hey guys am new to mysql development..I hve wrote some code like
CREATE TABLE CUSTOMERS(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25) ,
SALARY DECIMAL (18, 2),
PRIMARY KEY (ID)
);
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (1,'aff',2,3,5);
set #a := CASE WHEN NAME = 'aff' THEN 5 ELSE 3 END;
when i run the varibale #a it throws error like Schema Creation Failed: Unknown column 'NAME' in 'field list':
Can anyone help me ..An sql fiddle example would be realy apreciated ..Thanx
To get something from a table, you have to use a SELECT query:
SET #a := (SELECT CASE WHEN name = 'aff' THEN 5 ELSE 3 END
FROM CUSTOMERS
LIMIT 1);
DEMO
When using a SELECT as an expression, it must only return 1 row, that's why I added the LIMIT 1 clause.