SQL Server: Cannot insert an explicit value into a timestamp column - sql

When using this statement
create table demo (
ts timestamp
)
insert into demo select current_timestamp
I get the following error:
Cannot insert an explicit value into a timestamp column. Use INSERT with a column list to exclude the timestamp column, or insert a DEFAULT into the timestamp column
How do I insert the current time to a timestamp column?

According to MSDN, timestamp
Is a data type that exposes automatically generated, unique binary
numbers within a database. timestamp is generally used as a mechanism
for version-stamping table rows. The storage size is 8 bytes. The
timestamp data type is just an incrementing number and does not
preserve a date or a time. To record a date or time, use a datetime
data type.
You're probably looking for the datetime data type instead.

If you have a need to copy the exact same timestamp data, change the data type in the destination table from timestamp to binary(8) -- i used varbinary(8) and it worked fine.
This obviously breaks any timestamp functionality in the destination table, so make sure you're ok with that first.

You can't insert the values into timestamp column explicitly. It is auto-generated. Do not use this column in your insert statement. Refer http://msdn.microsoft.com/en-us/library/ms182776(SQL.90).aspx for more details.
You could use a datetime instead of a timestamp like this:
create table demo (
ts datetime
)
insert into demo select current_timestamp
select ts from demo
Returns:
2014-04-04 09:20:01.153

How to insert current time into a timestamp with SQL Server:
In newer versions of SQL Server, timestamp is renamed to RowVersion. Rightly so, because timestamp name is misleading.
SQL Server's timestamp IS NOT set by the user and does not represent a date or a time. Timestamp is only good for making sure a row hasn't changed since it's been read.
If you want to store a date or a time, do not use timestamp, you must use one of the other datatypes, like for example datetime, smalldatetime, date, time or DATETIME2
For example:
create table foo (
id INT,
leet timestamp
)
insert into foo (id) values (15)
select * from foo
15 0x00000000000007D3
'timestamp' in mssql is some kind of internal datatype. Casting that number to datetime produces a nonsense number.

Assume Table1 and Table2 have three columns A, B and TimeStamp. I want to insert from Table1 into Table2.
This fails with the timestamp error:
Insert Into Table2
Select Table1.A, Table1.B, Table1.TimeStamp From Table1
This works:
Insert Into Table2
Select Table1.A, Table1.B, null From Table1

There is some good information in these answers. Suppose you are dealing with databases which you can't alter, and that you are copying data from one version of the table to another, or from the same table in one database to another. Suppose also that there are lots of columns, and you either need data from all the columns, or the columns which you don't need don't have default values. You need to write a query with all the column names.
Here is a query which returns all the non-timestamp column names for a table, which you can cut and paste into your insert query. FYI: 189 is the type ID for timestamp.
declare #TableName nvarchar(50) = 'Product';
select stuff(
(select
', ' + columns.name
from
(select id from sysobjects where xtype = 'U' and name = #TableName) tables
inner join syscolumns columns on tables.id = columns.id
where columns.xtype <> 189
for xml path('')), 1, 2, '')
Just change the name of the table at the top from 'Product' to your table name. The query will return a list of column names:
ProductID, Name, ProductNumber, MakeFlag, FinishedGoodsFlag, Color, SafetyStockLevel, ReorderPoint, StandardCost, ListPrice, Size, SizeUnitMeasureCode, WeightUnitMeasureCode, Weight, DaysToManufacture, ProductLine, Class, Style, ProductSubcategoryID, ProductModelID, SellStartDate, SellEndDate, DiscontinuedDate, rowguid, ModifiedDate
If you are copying data from one database (DB1) to another database(DB2) you could use this query.
insert DB2.dbo.Product (ProductID, Name, ProductNumber, MakeFlag, FinishedGoodsFlag, Color, SafetyStockLevel, ReorderPoint, StandardCost, ListPrice, Size, SizeUnitMeasureCode, WeightUnitMeasureCode, Weight, DaysToManufacture, ProductLine, Class, Style, ProductSubcategoryID, ProductModelID, SellStartDate, SellEndDate, DiscontinuedDate, rowguid, ModifiedDate)
select ProductID, Name, ProductNumber, MakeFlag, FinishedGoodsFlag, Color, SafetyStockLevel, ReorderPoint, StandardCost, ListPrice, Size, SizeUnitMeasureCode, WeightUnitMeasureCode, Weight, DaysToManufacture, ProductLine, Class, Style, ProductSubcategoryID, ProductModelID, SellStartDate, SellEndDate, DiscontinuedDate, rowguid, ModifiedDate
from DB1.dbo.Product

create table demo (
id int,
ts timestamp
)
insert into demo(id,ts)
values (1, DEFAULT)

Related

How to aggregate rows into one month

I'm attempting to combine data that I am selecting from another table.
This table has a column named IdClient_PK which is a uniqueID and a column DateJoinKey which is the date this user viewed a page.
I would like to combine all DateJoinKey into one month. So For example:
IDClient_PK
DateJoinKey
Views
0E984725-C51C-4BF4-9960-E1C80E27ABA0
01-1-2021
2
0E984725-C51C-4BF4-9960-E1C80E27ABA0
01-3-2021
1
0E984725-C51C-4BF4-9960-E1C80E27ABA0
01-14-2021
3
0E984725-C51C-4BF4-9960-E1C80E27ABA0
01-21-2021
1
I'm attempting to get a result that looks like this:
IDClient_PK
DateJoinKey
Views
0E984725-C51C-4BF4-9960-E1C80E27ABA0
01-1-2021
7
How am I able to do this?
I attempted using the FORMAT() statement in SQL but I run into an error saying: Conversion failed when converting date and/or time from character string.
Here is an example of my query:
CREATE TABLE #tmpModule2(
[IdClient_PK] uniqueidentifier,
[DateJoinKey] DATETIME,
[Views] INT
)
INSERT INTO #tmpModule ([IdClient_PK],[DateJoinKey], [Views] )
SELECT a.[IdClient_PK],
FORMAT(a.DateJoinKey, 'yyyy-MM'),
SUM(a.ViewValue)
FROM [usage].[Fact_RegisteredUsers_UserReport] a
GROUP BY
a.IdClient_PK,
FORMAT(a.DateJoinKey, 'yyyy-MM'),
FORMAT() returns a NVARCHAR data type, but your temp table has that column as a DATETIME. You can either change your CREATE to use the proper data type or SELECT INTO like below. Or you could convert that returned column that you have above to a DATETIME before you insert into your temp table.
SELECT a.[IdClient_PK],
FORMAT(a.DateJoinKey, 'yyyy-MM') as [DateJoinKey],
SUM(a.ViewValue) AS [Views]
INTO #tmpModule
FROM [usage].[Fact_RegisteredUsers_UserReport] a
GROUP BY
a.IdClient_PK,
FORMAT(a.DateJoinKey, 'yyyy-MM')

Converting a column value from real data type to string during pattern matching in SQL query

I have a table in SQL database named 'customer' which has a column name called 'customer_no' of datatype real. data contained in the 'customer_no' column is as follows:
customer_no
........
........
54213154
11011011
11011012
11011013
11011014
11011215
11011015
11011101
45121478
........
........
I want to retrieve the column values that begin with 1101 using wildcard pattern matching. I am using SQL Server Management Studio. I have made the following SQL query to get the result:
select * from customer
where CONVERT(VARCHAR(100), customer_no) like '1101%';
But the problem is, I am getting 0 rows as output. Is there anything wrong in the above query? How can I get the desired result?
If customer number is an integer, why not use:
where customer_no >= 11010000 and
customer_no < 11020000
you need to convert the real to numeric first
CREATE TABLE #customer
(
customer_no real
)
INSERT INTO #customer(customer_no) SELECT 54213154
INSERT INTO #customer(customer_no) SELECT 11011011
INSERT INTO #customer(customer_no) SELECT 11011012
INSERT INTO #customer(customer_no) SELECT 11011013
INSERT INTO #customer(customer_no) SELECT 11011014
INSERT INTO #customer(customer_no) SELECT 11011215
INSERT INTO #customer(customer_no) SELECT 11011015
INSERT INTO #customer(customer_no) SELECT 11011101
INSERT INTO #customer(customer_no) SELECT 11021014
INSERT INTO #customer(customer_no) SELECT 45121478
SELECT * FROM #customer
WHERE CONVERT(VARCHAR(100),CONVERT(NUMERIC, customer_no)) like '1101%';
DROP TABLE #customer
When the values are converted to a characters representation it's using scientific notation which is why the pattern doesn't match.
Will math work?
where cast(floor(customer_no) as int) /
cast(power(10, floor(log10(customer_no) - 3)) as int) = 1101
-- note that floor(log10(1101)) = 3
The other advice you've gotten seems sound so this would really only apply if, for instance, the length of the id is variable. Using a floating point value for an id is only asking for headaches.

SQL Trigger to record UPDATE into Audit Table

I have a table with columns businessname, sortcode and accountnumber all populated, name, nationality and DOB all currently unpopulated. I need to create a trigger to shoot every update to an audit table when any of the null fields are updated so if I change just the name I'll get a timestamp, userid, the field changed, the old value and the new value.. If I changed all 3 null fields I'd like to send 3 rows to the audit table.
Can someone give me a pointer on the logic of this please?
In a very rudimentary format for testing I've got
CREATE TRIGGER RM_UPDATE_TRIGGER ON RM_BASE
ON UPDATE
AS
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, SRT_CD
FROM RM_BASE
but this is sending all the current rows across after an UPDATE to any of them, I only want the row that has been affected. I'm not sure if I should be building more tables to join together to get the final answer or using the INSERT/DELETE tables.. I've seen an audit table in this format in previous roles so I know it works but can't figure it out!
Thanks
Yes, you need to use the INSERTED and/or DELETED pseudo-tables as those contain only the rows that have been modified. As in:
CREATE TRIGGER RM_UPDATE_TRIGGER ON RM_BASE
ON UPDATE
AS
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, SRT_CD
FROM INSERTED
The INSERTED table has the "new" or "current" version of each row while the DELETED table has the "old" version that has been replaced via the UPDATE operation. This is the case for all versions of SQL Server, at least going back as far as SQL Server 2000.
In order to track the change itself (both "old" and "new" values), then you need to JOIN those two pseudo-tables, as in:
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, ins.SRT_CD AS [SRT_CD_new], del.SRT_CD AS [SRT_CD_old]
FROM INSERTED ins
INNER JOIN DELETED del
ON del.PKfield = ins.PKfield
This is the basic operation for capturing changes (unless, of course, you use Change Data Capture) in a DML trigger.
If you want to unpivot this data such that each set of "old" and "new" columns becomes a row, that should be easily adaptable from the above. In that case, you could also add WHERE ISNULL(ins.column, '~~~~') <> ISNULL(del.column, '~~~~') COLLATE Latin1_General_BIN to avoid capturing fields that have not changed. The COLLATE ensures case-sensitive / accent-sensitive / etc comparisons.
Of course, unpivoting makes it really hard to reconstruct the entire row as you are then required to keep the full history forever. You would need to start with the base values for all fields and apply the changes incrementally. The typical audit scenario is to just to capture the row that has fields for both old and new for each source field (like I have already shown). If your audit table looks more like:
PKfield, DateModified, businessname_old, businessname_new, sortcode_old, sortcode_new
then you can write a query to identify which fields actually changed by comparing each set (given that more than 1 field can change in the same UPDATE operation), something like:
SELECT PKfield,
DateModified,
CASE
WHEN ISNULL(businessname_old, '~~~~') <> ISNULL(businessname_new, '~~~~')
COLLATE Latin1_General_BIN THEN 'BusinessName ' ELSE ''
END +
CASE
WHEN ISNULL(sortcode_old, '~~~~') <> ISNULL(sortcode_new, '~~~~')
COLLATE Latin1_General_BIN THEN 'SortCode ' ELSE ''
END AS [FieldsChanged]
FROM AuditTable
ORDER BY DateModified DESC;
BUT, if you really want to unpivot the data to have one row per actual changed field, then the following structure should work:
;WITH ins AS
(
SELECT PKfield, FieldName, Value
FROM (
SELECT PKfield, businessname, sortcode, accountnumber, name,
nationality, DOB
FROM INSERTED
) cols
UNPIVOT (Value FOR FieldName IN
(businessname, sortcode, accountnumber, name, nationality, DOB)
) colvals
), del AS
(
SELECT PKfield, FieldName, Value
FROM (
SELECT PKfield, businessname, sortcode, accountnumber, name,
nationality, DOB
FROM DELETED
) cols
UNPIVOT (Value FOR FieldName IN
(businessname, sortcode, accountnumber, name, nationality, DOB)
) colvals
)
INSERT INTO AuditTable (PKfield, DateModified, FieldName, OldValue, NewValue)
SELECT ins.PKfield, CURRENT_TIMESTAMP, ins.FieldName, del.Value, ins.Value
FROM ins
INNER JOIN del
ON del.PKfield = ins.PKfield
AND del.FieldName = ins.FieldName
WHERE ISNULL(del.Value, '~~~~') <>
ISNULL(ins.Value, '~~~~') COLLATE Latin1_General_BIN;
You might need to add a CONVERT(VARCHAR(1000), field) to the WHERE condition if DOB is a DATE or DATETIME field, or if SRT_CD is an INT or other type of number field:
WHERE ISNULL(CONVERT(VARCHAR(1000), del.Value), '~~~~') <>
ISNULL(CONVERT(VARCHAR(1000), ins.Value), '~~~~')
COLLATE Latin1_General_BIN;

T-SQL Insert into table without having to specify every column

In our db there is a table that has a little over 80 columns. It has a primary key and Identity insert is turned on. I'm looking for a way to insert into this table every column EXCEPT the primary key column from an identical table in a different DB.
Is this possible?
You can do this quite easily actually:
-- Select everything into temp table
Select * Into
#tmpBigTable
From [YourBigTable]
-- Drop the Primary Key Column from the temp table
Alter Table #tmpBigTable Drop Column [PrimaryKeyColumn]
-- Insert that into your other big table
Insert Into [YourOtherBigTable]
Select * From #tmpBigTable
-- Drop the temp table you created
Drop Table #tmpBigTable
Provided you have Identity Insert On in "YourOtherBigTable" and columns are absolutely identical you will be okay.
You could query Information_Schema to get a list of all the columns and programatically generate the column names for your query. If you're doing this all in t-sql it would be cumbersome, but it could be done. If you're using some other client language, like C# to do the operation, it would be a little less cumbersome.
No, that's not possible. You could be tempted to use
INSERT INTO MyLargeTable SELECT * FROM OtherTable
But that would not work, because your identity column would be included in the *.
You could use
SET IDENTITY_INSERT MyLargeTable ON
INSERT INTO MyLargeTable SELECT * FROM OtherTable
SET IDENTITY_INSERT MyLargeTable OFF
first you enable inserting identity values, than you copy the records, then you enable the identity column again.
But this won't work neither. SQL server won't accept the * in this case. You have to explicitly include the Id in the script, like :
SET IDENTITY_INSERT MyLargeTable ON
INSERT INTO MyLargeTable (Id, co1, col2, ...., col80) SELECT Id, co1, col2, ...., col80 FROM OtherTable
SET IDENTITY_INSERT MyLargeTable OFF
So we're back from where we started.
The easiest way is to right click the table in Management Studio, let it generate the INSERT and SELECT scripts, and edit them a little to let them work together.
CREATE TABLE Tests
(
TestID int IDENTITY PRIMARY KEY,
A int,
B int,
C int
)
INSERT INTO dbo.Tests
VALUES (1,2,3)
SELECT * FROM Tests
This works in SQL2012
Why not just create a VIEW of the original data, removing the unwanted fields?
Then 'Select * into' your hearts desire.
Localized control within a single view
No need to modify SPROC
Add/change/delete fields easy
No need to query meta-data
No temporary tables
Really, honestly it takes ten seconds or less to pull all of the columns over from the object browser and then delete the identity column from the list. It is a bad idea to use select * for anything but quick ad hoc query.
In answer to a related question (SELECT * EXCEPT), I point out the truly relational language Tutorial D allows projection to be expressed in terms of the attributes to be removed instead of the ones to be kept e.g.
my_relvar { ALL BUT description }
However its INSERT syntax requires tuple value constructors to include attribute name / value pairs e.g.
INSERT P
RELATION
{
TUPLE { PNO PNO ( 'P1' ) , PNAME CHARACTER ( 'Nut' ) },
TUPLE { PNO PNO ( 'P2' ) , PNAME CHARACTER ( 'Bolt' ) }
};
Of course, using this syntax there is no column ordering (because it is truly relational!) e.g. this is semantically equivalent:
INSERT P
RELATION
{
TUPLE { PNO PNO ( 'P1' ) , PNAME CHARACTER ( 'Nut' ) },
TUPLE { PNAME CHARACTER ( 'Bolt' ) , PNO PNO ( 'P2' ) }
};
The alternative would be to rely fully on attribute ordering, which SQL does partially e.g. this is a close SQL equivalent to the the above:
INSERT INTO P ( PNO , PNAME )
VALUES
( PNO ( 'P1' ) , CAST ( 'Nut' AS VARCHAR ( 20 ) ) ) ,
( PNO ( 'P2' ) , CAST ( 'Bolt' AS VARCHAR ( 20 ) ) );
Once the commalist of columns has been specified the VALUES row constructors have the maintain this order, which is not ideal. But at least the order is specified: your proposal would rely on some default order which may be possibly non-deterministic.

setting data types in MS ACCESS SQL Insert queries

How can we explicitly convert data types in INSERT INTO/SELECT queries in MS Access?
Sample Query:
INSERT INTO pStudents( pStudentID, pDate, pRate, pGrade )
SELECT sStudentID, sDate, sRate, sGrade
FROM sStudents
WHERE (((sStudents.sStudentID) Is Not Null);
Here I want to convert fields from sStudents table before inserting in pStudents to following:
pStudentID = text
pDate = Short Date
pRate = Double
pGrade = text
Thanks in advance
You can use the built-in conversion functions of Access in the queries:
Select CStr(NumericColumn) from Table
...or as an INSERT query:
Insert Into AnotherTable (StringColumn)
Select CStr(NumericColumn) from Table
Did you mean something like that?
EDIT:
Okay, your sample query with conversions would look like this:
INSERT INTO pStudents( pStudentID, pDate, pRate, pGrade )
SELECT CStr(sStudentID), CDate(sDate), CDbl(sRate), CStr(sGrade)
FROM sStudents
WHERE (((sStudents.sStudentID) Is Not Null);
However, this will only work if the columns contain only data that can actually be converted into the given type.
For example, you can convert a String column to Double with CDbl() - but only if the selected rows contain only values that can actually be converted into Double.
As soon as you select one row with a value that contains something else than numeric values (like 'hello'), the conversion will fail.
On the other hand, do you really need the conversions?
Access can convert a lot by itself. For example, you can insert values from a numeric column into a string column, Access will convert it by itself. You don't have to use CStr() for that.
This should work. If you want Date, you can use CDate, however this will make sure the date is a short date (http://www.techonthenet.com/access/functions/date/format.php)
INSERT INTO pStudents( pStudentID, pDate, pRate, pGrade )
SELECT CStr(sStudentID), Format(sDate, "Short Date"), CDbl(sRate), CStr(sGrade)
FROM sStudents WHERE (((sStudents.sStudentID) Is Not Null);
There are many conversion function that are available in Access.
CBool(expression)
CByte(expression)
CCur(expression)
CDate(expression)
CDbl(expression)
CDec(expression)
CInt(expression)
CLng(expression)
CSng(expression)
CStr(expression)
CVar(expression)
http://office.microsoft.com/en-us/access-help/type-conversion-functions-HA001229018.aspx
Then you would use these functions in your INSERT INTO/SELECT query:
INSERT INTO table1 (field)...
SELECT Cstr(fieldValue)...
FROM table2
If you need to convert each of the fields in sStudents, then based on your edit you could do the following:
INSERT INTO pStudents( pStudentID, pDate, pRate, pGrade )
SELECT CStr(sStudentID), CDate(sDate), CDbl(sRate), CStr(sGrade)
FROM sStudents
WHERE (((sStudents.sStudentID) Is Not Null);