Timeout because of temp table - sql-server

In my stored procedure I'm using #temptable to fetch the data from one table and updating that #temptable for result. In my production environment this stored procedure is consuming a lot of time which is causing timeouts at times but in lower environment this query works absolute perfect.
CREATE TABLE #TempTable
(
ID int IDENTITY PRIMARY KEY,
TOTALPOLICY nvarchar(14),
SYMBOL nvarchar (3),
POLNUM nvarchar (7),
MODULE nvarchar (2),
LOC char (2),
MCO char (2),
LOB char (3),
INSUREDNAME nvarchar (100),
TotalPremium decimal (10,2),
ServiceCharges decimal (10,2),
TotalPaid decimal (10,2),
TotalRefunded decimal (10,2),
CurrentBalance decimal (10,2),
TotalBilled decimal (10,2),
PCO char (2)
)
INSERT INTO #TempTable (TOTALPOLICY,SYMBOL, POLNUM, MODULE, LOC, MCO, LOB, INSUREDNAME,TotalPremium, ServiceCharges, TotalPaid, TotalRefunded, CurrentBalance, TotalBilled, PCO) --PCR 109 SMT added PCO
EXEC(#sql)
--PCR 109 Start SMT
Update #TempTable
Set TotalPaid = IsNull((Select sum(PaymentAmt)
From SHCashActivity with (nolock)
Where #TempTable.POLNUM = PolicyNbr
and #TempTable.Module = PolicyModuleNbr
and #TempTable.Symbol = PolicySymbolCd
and CashActivityTypeCd in ('P', 'C', 'N')
and CashAppliedStatusCd in ('1','2')), 0)
Please advise me what could be solution for this .

The problem is not the temp table. The problem is the process takes too long. Re-architect your process so an answer is generated in a more acceptable length of time.
Also, your update statement is hard to read. It is also vulnerable to breaking if a field is added to SHCashActivity/#TempTable that matches the name of a field in the other table. Create table alias-es and use them for all field access.
Also,
create index X on #TempTable (POLNUM, Module, Symbol)
will help. The correct order of the fields in the index will depend upon indexes on SHCashActivity.

Related

SQL Server Sort varchar columns depend on numbers inside like int and decimal

Hello looking solution to sort sizes inside my column.
Exmaple :
-- CREATE TEMP TABLE
Create Table #MyTempTable (
size varchar(20)
);
-- insert sample data to TEMP TABLE
insert into #MyTempTable
values
('10.5W'),
('10W'),
('11.5W'),
('11W'),
('12W'),
('5.5W'),
('5W'),
('6.5W'),
('6W'),
('7.5W'),
('7W'),
('8.5W'),
('8W'),
('9.5W'),
('9W'),
('4')
select 'BEFORE',* from #MyTempTable
SELECT 'AFTER',size
FROM #MyTempTable
ORDER BY LEN(size)
When i order by LEN there is no good sorting like this :
AFTER 5W
AFTER 6W
AFTER 7W
AFTER 8W
AFTER 9W
AFTER 10W
AFTER 11W
AFTER 12W
AFTER 5.5W
AFTER 7.5W
AFTER 6.5W
AFTER 9.5W
AFTER 8.5W
AFTER 10.5W
AFTER 11.5W
All im' looking for is to sort in proper order. like this :
5W
5.5W
6W
6.5W
7W
7.5W
8W
8.5W
9W
9.5W
10W
10.5W
11W
11.5W
12W
I seearched a lot of stackoverflow and can't find solution for that because there is not only int and also decimal numbers. So don't know how to get it
Assuming each value would always end in just one unit, you may sort on the numeric portion cast to a decimal:
SELECT size
FROM #MyTempTable
ORDER BY CAST(
CASE WHEN size LIKE '%[A-Z]'
THEN LEFT(size, LEN(size) - 1)
ELSE size END AS DECIMAL(10, 2)
);
A couple of other options:
-- if you don't know all of the potential non-numeric characters:
SELECT size FROM #MyTempTable
ORDER BY TRY_CONVERT(decimal(5,2),
SUBSTRING(size,1,COALESCE(NULLIF
(PATINDEX('%[^0-9.]%', size),0),255)-1));
-- if there is a finite set (say, W and D):
DECLARE #KnownChars varchar(32) = 'WD';
SELECT size FROM #MyTempTable
ORDER BY TRY_CONVERT(decimal(5,2),
TRANSLATE(size, #KnownChars, REPLICATE(space(1), LEN(#KnownChars))));
In order by clause first remove W from then cast as NUMERIC data type. Now you can expect sorting like a number.
SELECT *
FROM #MyTempTable AS mtt
ORDER BY CAST(LEFT(mtt.size, LEN(mtt.size) - 1) AS DECIMAL) ASC;

'String or binary data would be truncated' without any data exceeding the length

Yesterday suddenly a report occurred that someone was not able to get some data anymore because the issue Msg 2628, Level 16, State 1, Line 57 String or binary data would be truncated in table 'tempdb.dbo.#BC6D141E', column 'string_2'. Truncated value: '!012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'. appeared.
I was unable to create a repro without our tables. This is the closest as I can get to:
-- Create temporary table for results
DECLARE #results TABLE (
string_1 nvarchar(100) NOT NULL,
string_2 nvarchar(100) NOT NULL
);
CREATE TABLE #table (
T_ID BIGINT NULL,
T_STRING NVARCHAR(1000) NOT NULL
);
INSERT INTO #table VALUES
(NULL, '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'),
(NULL, '!0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789!');
WITH abc AS
(
SELECT
'' AS STRING_1,
t.T_STRING AS STRING_2
FROM
UT
INNER JOIN UTT ON UTT.UT_ID = UT.UT_ID
INNER JOIN MV ON MV.UTT_ID = UTT.UTT_ID
INNER JOIN OT ON OT.OT_ID = MV.OT_ID
INNER JOIN #table AS T ON T.T_ID = OT.T_ID -- this will never get hit because T_ID of #table is NULL
)
INSERT INTO #results
SELECT STRING_1, STRING_2 FROM abc
ORDER BY LEN(STRING_2) DESC
DROP TABLE #table;
As you can see the join of #table cannot yield any results because all T_ID are NULL nevertheless I am getting the error mentioned above. The result set is empty.
That would be okay if a text with more than 100 characters would be in the result set but that is not the case because it is empty. If I remove the INSERT INTO #results and display the results it does not contain any text with more than 100 characters. The ORDER BY was only used to determine the faulty text value (with the original data).
When I use SELECT STRING_1, LEFT(STRING_2, 100) FROM abc it does work but it does not contain the text either that is meant to be truncated.
Therefore: What am I missing? Is it a bug of SQL Server?
-- this will never get hit is a bad assumption. It is well known and documented that SQL Server may try to evaluate parts of your query before it's obvious that the result is impossible.
A much simpler repro (from this post and this db<>fiddle):
CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id) VALUES (1), (3), (4), (5);
GO
DECLARE #t table(dest varchar(3) NOT NULL);
INSERT #t(dest) SELECT t1.s
FROM dbo.t1
INNER JOIN dbo.t2 ON t1.id = t2.id;
Result:
Msg 2628, Level 16, State 1
String or binary data would be truncated in table 'tempdb.dbo.#AC65D70E', column 'dest'. Truncated value: 'len'.
While we should have only retrieved rows with values that fit in the destination column (id is 1 or 3, since those are the only two rows that match the join criteria), the error message indicates that the row where id is 2 was also returned, even though we know it couldn't possibly have been.
Here's the estimated plan:
This shows that SQL Server expected to convert all of the values in t1 before the filter eliminated the longer ones. And it's very difficult to predict or control when SQL Server will process your query in an order you don't expect - you can try with query hints that attempt to either force order or to stay away from hash joins but those can cause other, more severe problems later.
The best fix is to size the temp table to match the source (in other words, make it large enough to fit any value from the source). The blog post and db<>fiddle explain some other ways to work around the issue, but declaring columns to be wide enough is the simplest and least intrusive.

SSMS - Trying to Bulk insert into a table but decimal field sometimes contains NA

I have tried to create a new table where the column is just varchar(100), but it gives the same conversion error. Most of the column consists of decimal numbers, but instead of putting null or leaving blank when no decimal found the company put NA for NULL values.
The file will not bulk insert since sometimes there are a significant amount of NA's in the decimal column.
Not sure how to get around the problem. My Bulk Insert (again, i have tried to use varchar(100) for the field and decimal (18,2) but get the same data conversion error
Bulk Insert MyExistingTable
From '\\myfile.TXT'
With (
FIELDTERMINATOR = '|',
ROWTERMINATOR = '0x0a',
BATCHSIZE = 10000
)
Once you've succeeded in loading, for example, a 2 column csv (one column is text, the other is a decimal number but sometimes literal text 'NA' instead of null/empty) you can move data like this:
INSERT INTO main(maintextcol, maindeccol)
SELECT temptextcol, NULLIF(tempdeccol, 'NA') from tmp
The conversion from text to decimal is implicit. If you have more columns, add them to the query (I made it 2 to keep life simple)
If you want to avoid duplicates in your main table because some data in tmp is already in main:
INSERT INTO main(maintextcol, maindeccol)
SELECT t.temptextcol, NULLIF(t.tempdeccol, 'NA')
FROM
tmp t
LEFT JOIN
main m
ON m.maintextcol = t.temptextcol -- the xxxtextcol columns define the ID in each table
WHERE
m.maintextcol is null
The left join will create nulls in maintextcol if there is no match so this is one of the rows we want to insert. The where clause finds rows like this
Demo of the simple scenario:
create table main(a varchar(100), b decimal(18,2
))
GO
✓
create table tmp (a varchar(100), b varchar(100))
GO
✓
insert into tmp values('a', '10.1'),
('b', 'NA')
GO
2 rows affected
insert into main
select a, NULLIF(b, 'NA') from tmp
GO
2 rows affected
select * from main
GO
a | b
:- | :----
a | 10.10
b | null
db<>fiddle here

Computed column value not the same as Scalar Function it uses

I have a Table with a computed column that uses a scalar function
CREATE FUNCTION [dbo].[ConvertToMillimetres]
(
#fromUnitOfMeasure int,
#value decimal(18,4)
)
RETURNS decimal(18,2)
WITH SCHEMABINDING
AS
BEGIN
RETURN
CASE
WHEN #fromUnitOfMeasure=1 THEN #value
WHEN #fromUnitOfMeasure=2 THEN #value * 100
WHEN #fromUnitOfMeasure=3 THEN #value * 1000
WHEN #fromUnitOfMeasure=4 THEN #value * 25.4
ELSE #value
END
END
GO
The table has this column
[LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED,
Assuming that the [Length] on the Table is 62.01249 and [LengthUnitOfMeasure] is 4 the LengthInMm computed value comes with 1575.11 but when i run the function directly like
SELECT [dbo].[ConvertToMillimetres] (4, 62.01249) GO
It comes with 1575.12
[Length] column is (decimal(18,4, null))
Can anyone tell why this happens?
I'm not sure this really counts as an answer, but you've perhaps got a problem with a specific version of SQL?
I just had a go at replicating it (on a local SQL 2014 install) and got the following:
create table dbo.Widgets (
Name varchar(20),
Length decimal(18,4),
LengthInMm AS [dbo].[ConvertToMillimetres] (4, Length) PERSISTED
)
insert into dbo.Widgets (Name, Length) values ('Thingy', 62.01249)
select * from dbo.Widgets
Which gives the result:
Name Length LengthInMm
-------------------- --------------------------------------- ---------------------------------------
Thingy 62.0125 1575.12
(1 row(s) affected)
Note that your definition uses [LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED, but that doesn't seem to make a difference to the result.
I also tried on my PC (Microsoft SQL Server 2012 - 11.0.2100.60 (X64)). Works fine:
CREATE TABLE dbo.data(
LengthUnitOfMeasure INT,
[Length] decimal(18,4),
[LengthInMm] AS (CONVERT([decimal](18,2),[dbo].[ConvertToMillimetres]([LengthUnitOfMeasure],[Length]))) PERSISTED
)
INSERT INTO dbo.data (LengthUnitOfMeasure, [Length])
SELECT 4, 62.01249
SELECT *
FROM dbo.data
/*
RESULT
LengthUnitOfMeasure Length LengthInMm
4 62.0125 1575.12
*/
I think, I found the answer:
Lets see what you are saying:
There is a column with decimal(18,4) data type.
There is a calculated column which depend on this column.
The result differs when you select the calculated field and when you provide the same result manually. (Right?)
Sorry, but the input parameters are not the same:
The column in the table is decimal(18,4). The value you are provided manually is decimal(7,5) (62.01249)
Since the column in the table can not store any values with scale of 5, the provided values will not be equal. (Furthermore there is no record in the table with the value of 62.01249 in the Length column)
What is the output when you query the [Length] column from the table? Is it 62.0124? If yes, then this is the answer. The results can not be equal since the input values are not equal.
To be a bit more specific: 62.01249 will be casted (implicit cast) to 62.0125.
ROUND(25.4 * 62.0124, 2) = 1575.11
ROUND(25.4 * 62.0125, 2) = 1575.12
EDIT Everybody who tried to rebuild the schema made the same mistake (Including me). When we (blindly) inserted the values from the original question into our instances, we inserted the 62.01249 into the Length column -> the same implicit cast occured, so we have the value 62.0125 in our tables.

SQL Server hexadecimal handling

I believe I'm having a problem with the way SQL Server 2000 handles hexadecimal numbers.
If I do a
select * from table where [timestamp] = 44731446
the row that it returns shows the timestamp as 0x0000000202AA8C36
Equally in another table if I
select * from table2 where [timestamp] = 44731446
the row that it returns shows the timestamp as 0x0000000002AA8C36 (notice the missing 2)
MS Calc tells me that the first timestamp = 8634666038 in decimal and the second timestamp = 44731446 in decimal which matches my original query on both tables.
So why is SQL Server returning a different number, yet successfully querying it? I believe this is the route of an update problem I'm having where the row won't update.
Long story short, the binary to integer conversion is truncating data:
select cast(0x0000000202AA8C36 as int)
A TIMESTAMP column is really BINARY(8), so your query is comparing a BINARY(8) value to an INT value; because INT has the higher precedence, MSSQL converts the BINARY(8) value to INT before comparing them.
But, 0x0000000202AA8C36 (or 8634666038) is too big to be represented as INT, so MSSQL has to truncate it first, and it truncates to the same value as 0x0000000002AA8C36. This might be a little clearer:
create table dbo.t (tstamp binary(8) not null)
go
insert into dbo.t values (0x0000000202AA8C36)
insert into dbo.t values (0x0000000002AA8C36)
go
-- returns 2 rows
select * from dbo.t where tstamp = 44731446
-- returns 1 row
select * from dbo.t where tstamp = cast(44731446 as bigint)
go
drop table dbo.t
go
According to Books Online (for 2008, I don't have 2000):
When [non-string data types] are converted to
binary or varbinary, the data is
padded or truncated on the left.
Padding is achieved by using
hexadecimal zeros

Resources