Assuming your current table is something like
CREATE TABLE YourTable
(
Id INT IDENTITY PRIMARY KEY,
OtherColumns VARCHAR(10)
)
And that your existing code that references the table just performs basic DQL and DML commands against the table (i.e. SELECT
/UPDATE
,MERGE
,INSERT
,DELETE
)
And that YourTable(Id)
isn't referenced by a foreign key anywhere.
Then possibly the best way of getting up and running quickly (if you can't afford the downtime of rebuilding the whole table in one go) would be to rename that table (e.g. as YourTableInt
) and create a new table
CREATE TABLE YourTableBigInt
(
Id BIGINT IDENTITY(2147483648, 1) PRIMARY KEY,
OtherColumns VARCHAR(10)
)
You could then create a view with the same name as your original table name.
CREATE VIEW YourTable
AS
SELECT Id,
OtherColumns
FROM YourTableInt
UNION ALL
SELECT Id,
OtherColumns
FROM YourTableBigInt
You would need to write INSTEAD OF
triggers that route the Inserts/Updates/Deletes to the appropriate table. This could initially be based on whether Id was <= 2147483647 or not but that isn't going to work if you try and migrate rows in the background from the legacy table to the new one so probably best to do the following.
Delete trigger
Apply deletes against both tables by joining on id
Update trigger
Apply updates to both tables by joining on id
Insert trigger
Route all inserts into the new "YourTableBigInt" table. It shouldn't be possible for an insert through the view to enter an explicit identity that might clash with anything in the original table as any attempt to set identity_insert YourTable
will fail now that is actually a view.
You could then have a background process that deletes batches of rows from YourTableInt
and output
s them into YourTableBigInt
. Once the original table is empty you can drop it and the view and rename YourTableBigInt to YourTable.
The rules that SQL Server uses to derive the type of literals are complex, with some odd behaviours that are maintained these days for backward compatibility. For example, the derived type may depend on whether simple parameterization is applied. There are other (undocumented) considerations as well.
With those caveats out of the way, the situation you face is one of the simpler ones. The untyped literals are typed as integer
when they will fit in that data type. The data type of the result is as specified in * (Multiply) (Transact-SQL):
Returns the data type of the argument with the higher precedence.
For more information, see Data Type Precedence (Transact-SQL).
The two data types are both integer
(with obviously the same precedence), so the result is also typed as integer
. When the result does not fit, an error may be thrown (depending on settings).
When one of the literals is explicitly typed using CAST
or CONVERT
as (for example) bigint
(which has a higher precedence than integer
) the result type will be bigint
, and no error occurs.
The two larger constants in the question are typed as numeric(24,0)
and numeric(12,0)
respectively. The result of multiplying them is typed as numeric(37,0)
in accordance with the rules for e1 * e2
shown in Precision, Scale, and Length (Transact-SQL):
Result precision: p1 + p2 + 1 = 24 + 12 + 1 = 37
Result scale: s1 + s2 = 0 + 0 = 0
Result type: numeric (37,0)
Best Answer
For values larger than the
INT
max (2,147,483,647), you'll want to use COUNT_BIG(*).If it's happening in the
SUM
, you need to convertAmount
to aBIGINT
.