Error in store procedure execution - sql

When I am trying t execute a stored procedure, It is showing this error
Msg 8152, Level 16, State 14, Procedure MA01003_SUM1, Line 12
String or binary data would be truncated.
The statement has been terminated.
Following is the stored procedure
ALTER procedure [dbo].[MA01003_SUM1]
as
Begin
declare #desc as varchar(50)
set #desc = dbo.sdescription(1,0,3)
declare #cost as float
set #cost = dbo.SCost(0)
Insert into SummaryLoad(
SL_TierName,
SL_CorporateName,
SL_HospiceName,
SL_GroupName,
SL_DateKey,
SL_FactAmt,
SL_AHT,
SL_headingNo,
SL_Staffno,
SL_factno,
SL_Description,
SL_Cost)
SELECT [MA_TierName]
,[MA_CorporateName]
,[MA_HospiceName]
,[MA_GroupName]
,[MA_Datekey]
,SUM([MA_NumContacts]) Contacts
,SUM([MA_Duration]) ActualHandleTime,
'1',
'0',
'3',
#desc,
#cost
FROM [DM_ResourceUtilization].[dbo].[MedicationsAdded]
GROUP BY [MA_TierName]
,[MA_CorporateName]
,[MA_HospiceName]
,[MA_GroupName]
,[MA_Datekey]
end

Probable are the chances that data type or width of table SummaryLoad is not matching with that of select statement output. Please see the following script to illustrate the concept -
use tempdb
go
create table #test ( c1 varchar(5))
go
declare #desc as varchar(10) -- Width is 10 only
set #desc = 'AAAAAABBBBBBBBBBBbbCCCCCCCCCCCCCCcDDDDDDDDDDDDDD' -- Assigning higher width value
select #desc -- No error thrown, SQL server do the data truncation silently
insert into #test(c1) values ( #desc ) -- Here SQL server throws an error,
-- reason - value in #desc is of width 10, but target column width is 5
Better you can find the offending column or statement by yourself without much difficulty. To do this comment out each column and its values from the procedure and then invoke it in a transaction OR give a constant value that would match with the target data type for each column one by one. Sample follows -
Insert into SummaryLoad(
SL_TierName,
SL_CorporateName,
SL_HospiceName,
SL_GroupName,
SL_DateKey,
SL_FactAmt,
SL_AHT,
SL_headingNo,
SL_Staffno,
SL_factno,
SL_Description,
SL_Cost)
SELECT
/*[MA_TierName] */ -- Commented out
'A' -- Sample value, alter the procedure with this insert and run in transaction
-- If that is successful, this is offending column. Change the value with matching
-- data type and width of column SL_TierName of table SummaryLoad
-- Repeat this for all columns till you find the offending column(s)
,[MA_CorporateName]
,[MA_HospiceName]
,[MA_GroupName]
,[MA_Datekey]
,SUM([MA_NumContacts]) Contacts
,SUM([MA_Duration]) ActualHandleTime,
'1',
'0',
'3',
#desc,
#cost
FROM [DM_ResourceUtilization].[dbo].[MedicationsAdded]
GROUP BY [MA_TierName]
,[MA_CorporateName]
,[MA_HospiceName]
,[MA_GroupName]
,[MA_Datekey]
Modified procedure should be called in a transaction to ensure that your data is not affected by this test. Procedure can be called in a transaction using following statement
begin transaction
exec [dbo].[MA01003_SUM1]
rollback transaction

As per your error message :
Msg 8152, Level 16, State 14, Procedure MA01003_SUM1, Line 12
String or binary data would be truncated.
The statement has been terminated.
It is possibly your column width issue which is overlapped or oveflow then the size defined in column.
So, you have to just check which column have how much size & what you passing the data (i.e. size of data) which greater then size defined in column.

Related

How to insert a cast conversion into database

I've been trying to insert a varchar value into a table in SQL using a cast.
The varchar input values has a string datetime format like this:
'08/25/2022 03:34:59 PM'
The fechaInicio column is originally filled with NULL, and the purpose of the stored procedure is to update that column with the #strDateTime value sent.
Example of my table [Table_Input]:
fechaInicio
ID
NULL
2
If I just do a
SELECT CAST('08/25/2022 03:34:59 PM' AS DATETIME)
it actually works and shows me the correct casting in the message window. But the problem is when I try to update into the table.
I removed my try-except commands to see the error.
If I call the stored procedure like this
[SP_Table_Input_Get_Series] '08/25/2022 03:34:59 PM', 2
I get the following error:
Msg 241, Level 16, State 1, Procedure SP_Table_Input_Get_Series, Line 34 [Batch Start Line 13]
Conversion failed when converting date and/or time from character string
My stored procedure is something like this:
PROCEDURE [SP_Table_Input_Get_Series]
#strDateTime NVARCHAR(50),
#cId int
AS
BEGIN TRANSACTION
UPDATE [Table_Input]
SET
---fechaInicio =convert(datetime, #strDateTime, 5),
---fechaInicio = N'select cast(#strDateTime as datetime)'
fechaInicio = CAST(#strDateTime AS datetime)
WHERE id = #cId -- the where clause works fine
COMMIT TRANSACTION
All the 3 options (including commented ones in the stored procedure) didn't work.
Also a constraint is I cannot modify the column type to varchar or any other type.
I will really appreciated if someone can help me find a solution.
I'm running the stored procedure directly in Microsoft SQL Server Management Studio.
Please try the following solution.
As #AlwaysLearning pointed out, I changed 89 to 59 seconds.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, fechaInicio DATETIME2(0));
INSERT #tbl (fechaInicio) VALUES
(GETDATE());
-- DDL and sample data population, end
DECLARE #strDateTime VARCHAR(50) = '08/25/2022 03:34:59 PM';
-- before
SELECT * FROM #tbl;
UPDATE #tbl
SET fechaInicio = convert(DATETIME2(0), #strDateTime, 101)
where ID = 1;
-- after
SELECT * FROM #tbl;
Output
ID
fechaInicio
1
2022-08-25 15:34:59

Create a procedure to insert multiple values into a table, using a single variable

Goal: To create a procedure to insert multiple values into a table, using a single variable.
Challenge: Instead of making multiple hits in the same table, I have created a single variable (#SQL) and stored multiple columns (fm_id and shdl_id ) results in it but I am unable to use this single variable in the insert statement.
Code:
create proc abc
(
#org_id numeric(10,0),
#shdl_id numeric(10,0),
#usr_id numeric(10,0),
#tst_id numeric(10,0)
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #SQL NUMERIC(10);
SET #SQL= (SELECT fm_id,#shdl_id FROM [dbo].[students] WHERE ORG_ID=#org_id AND shdl_id=#shdl_id AND TST_ID=#tst_id)
INSERT INTO [USER]
SELECT org_id,#usr_id,TST_ID,login_name,#SQL FROM [students] WHERE ORG_ID=#org_id AND shdl_id=#shdl_id AND TST_ID=#tst_id
END
GO
Error :
Msg 213, Level 16, State 1, Procedure abc, Line 14 [Batch Start Line
94] Column name or number of supplied values does not match table
definition.
First you need to make your SELECT return only one value into the variable. There's no point selecting #shdl_id because you already know it?
DECLARE #pFMID NUMERIC(10);
SELECT #pFMID = MAX(fm_id) FROM [dbo].[students] WHERE ORG_ID=#org_id AND shdl_id=#shdl_id AND TST_ID=#tst_id);
Then because you're not inserting a value into every column in the user table you need to explicitly state which columns to fill. Replace x1..x5 below with real column names (in the order the SELECT has them)
INSERT INTO [USER](x1,x2,x3,x4,x5)
-- ^^^^^^^^^^^^^^^
-- REPLACE THESE WITH REAL NAME
SELECT org_id,#usr_id,TST_ID,login_name,#pFMID FROM [students] WHERE ORG_ID=#org_id AND shdl_id=#shdl_id AND TST_ID=#tst_id
END
GO
And as Uueerdo pointed out, this first query is a bit of a waste of time, we can write this:
create proc abc
(
...
)
AS
BEGIN
INSERT INTO [USER](x1,x2,x3,x4,x5)
SELECT org_id,#usr_id,TST_ID,login_name,fm_id FROM [students] WHERE ORG_ID=#org_id AND shdl_id=#shdl_id AND TST_ID=#tst_id
-- ^^^^^
-- look!
You can only get away with leaving the column list off an INSERT if you're inserting the same number of columns the table has:
CREATE TABLE x(col1 INT, col2 INT);
INSERT INTO x VALUES (1,2) -- works
INSERT INTO x VALUES (1) -- fails: which column should have the 1?
INSERT INTO x(col1) VALUES (1) -- works: col1 shall have the 1

SQL Server Conversion Failure when using INSERT

I have an existing table full of data, which can be created using
CREATE TABLE __EpisodeCost
(
ActivityRecordID INT NOT NULL,
ActCstID NVARCHAR(15),
VolAmt FLOAT,
ActCnt FLOAT,
TotCst FLOAT,
ResCstID NVARCHAR(50)
);
This comes from a feed I have no control over and I want to convert this to my own version called EpisodeCost
CREATE TABLE EpisodeCostCtp
(
ActivityRecordID INT NOT NULL,
ActCstID NVARCHAR(6),
ResCstID NVARCHAR(7),
ActCnt NVARCHAR(7),
TotCst DECIMAL(18, 8)
);
Now, the problem I am having is with conversions. I can execute the query
SELECT
ActivityRecordID,
Cast(ActCstID AS NVARCHAR(6)),
Cast(ResCstID AS NVARCHAR(7)),
Cast(LTRIM(STR(ActCnt, 10)) AS NVARCHAR(7)),
Cast(TotCst AS DECIMAL(18, 8))
FROM __EpisodeCostCtp;
and it provides data, however, when I try to execute
INSERT INTO EpisodeCostCtp
(
ActivityRecordID,
ActCstID,
ResCstID,
ActCnt,
TotCst
)
SELECT
ActivityRecordID,
Cast(ActCstID AS NVARCHAR(6)),
Cast(ResCstID AS NVARCHAR(7)),
Cast(LTRIM(STR(ActCnt, 10)) AS NVARCHAR(7)),
Cast(TotCst AS DECIMAL(18, 8))
FROM __EpisodeCostCtp;
I get
Msg 8115, Level 16, State 8, Line 102
Arithmetic overflow error converting numeric to data type numeric.
The statement has been terminated.
Why can I SELECT using the relevant casts, but then cannot INSERT into the target table?
Edit. I still don;t fully know what is occurring here.
As per Serg's recommendations, I have attempted to locate the problematic records but the query
SELECT
ActivityRecordID,
Cast(ActCstID AS NVARCHAR(6)),
Cast(ResCstID AS NVARCHAR(7)),
Cast(LTRIM(STR(ActCnt, 10)) AS NVARCHAR(7)),
Cast(TotCst AS DECIMAL(18, 8))
FROM __EpisodeCostCtp
WHERE TotCst > 9.999999999999999e9;
returns zero records. Changing to 9.999999999999999e8 does, and the conversion/cast happens with out error. I have scince changed the INSERT query to use DECIMAL(36, 18) and now the insert succeeds, but I am still none the wiser. Clearly I was hitting a limit on the cast, but why SELECT works and INSERT fails, I still don't know.
as is an overflow issue you might want to try
SET ARITHABORT OFF
from https://learn.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql
When an INSERT statement encounters an arithmetic error (overflow,
divide by zero, or a domain error) occurring during expression
evaluation, the Database Engine handles these errors as if SET
ARITHABORT is set to ON. The batch is stopped, and an error message is
returned. During expression evaluation when SET ARITHABORT and SET
ANSI_WARNINGS are OFF, if an INSERT, DELETE or UPDATE statement
encounters an arithmetic error, overflow, divide-by-zero, or a domain
error, SQL Server inserts or updates a NULL value. If the target
column is not nullable, the insert or update action fails and the user
receives an error.
I believe that in your TotCst column has values bigger than DECIMAL(18,8).
And the version 2008 of SQL SERVER gets a rounded result if the destination type is not large enough. But it can't insert because the table accepts exact values only.
You can see the result of my two queries on SQL SERVER 2012 :
DECLARE #float FLOAT
SET #float = 12345678911.12
SELECT CAST(#float AS decimal(18,8))
Result :
An arithmetic overflow error occurred when converting float to numeric data type.
the same query with DECIMAL(19,8) instead :
DECLARE #float FLOAT
SET #float = 12345678911.12
SELECT CAST(#float AS decimal(19,8))
Result : 12345678911.12000100
EDIT : Check if your query tool fetchs all records. If not, maybe among the rest of records there are some values bigger than DECIMAL(18.8)
To find rows which cause the problem try
SELECT *
FROM __EpisodeCostCtp
WHERE TotCst > 9.999999999999999e9;

SQL Server parameterized SELECT procedure returns no result, but returns records when set explicitly

I'm having problems with the following procedure
CREATE PROCEDURE [dbo].[Q2_05] (#Ch1 nvarchar, #Ch4 nvarchar, #globalOptionCode nvarchar)
AS
BEGIN
SET NOCOUNT ON;
SELECT [2_05].Ch1, [2_05].Ch4, [2_05].GlobalOption, [2_05].Part, [2_05].[Key]
FROM [dbo.NV300Autostructure].[2_05]
WHERE ((([2_05].Ch1)=#Ch1) AND (([2_05].Ch4)=#Ch4) AND (([2_05].GlobalOption)=#globalOptionCode));
END
when I execute it with the following parameters ('5', 'TH', '.') it returns no results, but in the process of elimination I found that modifying the conditions line and set [2_05].Ch4 explicitly to 'TH' like so:
WHERE ((([2_05].Ch1)=#Ch1) AND (([2_05].Ch4)='TH') AND (([2_05].GlobalOption)=#globalOptionCode));
it returns a row of the database. Why is that happening?
You are not specifying a size for your nvarchar parameters. The default is 1 character.
So the procedure is testing for [2_05].Ch4)='T' when you use the parameters.

String or binary data would be truncated. The statement has been terminated

I have met some problem with the SQL server, this is the function I created:
ALTER FUNCTION [dbo].[testing1](#price int)
RETURNS #trackingItems1 TABLE (
item nvarchar NULL,
warehouse nvarchar NULL,
price int NULL
)
AS
BEGIN
INSERT INTO #trackingItems1(item, warehouse, price)
SELECT ta.item, ta.warehouse, ta.price
FROM stock ta
WHERE ta.price >= #price;
RETURN;
END;
When I write a query to use that function like the following it getting the error
String or binary data would be truncated. The statement has been terminated
How can I fix this problem?
select * from testing1(2)
This is the way I create the table
CREATE TABLE stock(item nvarchar(50) NULL,
warehouse nvarchar(50) NULL,
price int NULL);
When you define varchar etc without a length, the default is 1.
When n is not specified in a data definition or variable declaration statement, the default length is 1. When n is not specified with the CAST function, the default length is 30.
So, if you expect 400 bytes in the #trackingItems1 column from stock, use nvarchar(400).
Otherwise, you are trying to fit >1 character into nvarchar(1) = fail
As a comment, this is bad use of table value function too because it is "multi statement". It can be written like this and it will run better
ALTER FUNCTION [dbo].[testing1](#price int)
RETURNS
AS
SELECT ta.item, ta.warehouse, ta.price
FROM stock ta
WHERE ta.price >= #price;
Of course, you could just use a normal SELECT statement..
The maximal length of the target column is shorter than the value you try to insert.
Rightclick the table in SQL manager and go to 'Design' to visualize your table structure and column definitions.
Edit:
Try to set a length on your nvarchar inserts thats the same or shorter than whats defined in your table.
In my case, I was getting this error because my table had
varchar(50)
but I was injecting 67 character long string, which resulted in thi error. Changing it to
varchar(255)
fixed the problem.
Specify a size for the item and warehouse like in the [dbo].[testing1] FUNCTION
#trackingItems1 TABLE (
item nvarchar(25) NULL, -- 25 OR equal size of your item column
warehouse nvarchar(25) NULL, -- same as above
price int NULL
)
Since in MSSQL only saying only nvarchar is equal to nvarchar(1) hence the values of the column from the stock table are truncated
SQL Server 2016 SP2 CU6 and SQL Server 2017 CU12
introduced trace flag 460 in order to return the details of truncation warnings.
You can enable it at the query level or at the server level.
Query level
INSERT INTO dbo.TEST (ColumnTest)
VALUES (‘Test truncation warnings’)
OPTION (QUERYTRACEON 460);
GO
Server Level
DBCC TRACEON(460, -1);
GO
From SQL Server 2019 you can enable it at database level:
ALTER DATABASE SCOPED CONFIGURATION
SET VERBOSE_TRUNCATION_WARNINGS = ON;
The old output message is:
Msg 8152, Level 16, State 30, Line 13
String or binary data would be truncated.
The statement has been terminated.
The new output message is:
Msg 2628, Level 16, State 1, Line 30
String or binary data would be truncated in table 'DbTest.dbo.TEST', column 'ColumnTest'. Truncated value: ‘Test truncation warnings‘'.
In a future SQL Server 2019 release, message 2628 will replace message 8152 by default.