ANSI_PADDING on varbinary(16) not working - sql

When I add a new fixed-length varbinary column with a default constraint of 0x00000000000000000000000000000000 to an existing non-empty table, the existing records in the table are receiving a trimmed version of the default constraint, 0x00.
Subsequent inserts of new records do correctly apply the default constraint.
This only occurs in SQL 2017, previous versions of SQL correctly apply the default constraint to all existing records.
Including 'SET ANSI_PADDING ON' does not impact the result.
0x11111111110000000... also behaves in same manner, where it trims the trailing zeroes.
I have also tried using a default of DEFAULT Cast(0x00000000000000000000000000000000 as varbinary(16)), but it has the same result.
Running Microsoft SQL Server 2017 (RTM-CU11) (KB4462262) - 14.0.3038.14 (X64)
To reproduce:
create table #test (id int);
insert into #test (id) values (1), (2), (3);
alter table #test add testvarbinary VARBINARY(16) NOT NULL CONSTRAINT
DF_MyTable_NewColumn DEFAULT 0x00000000000000000000000000000000;
insert into #test (id) values (4);
select * from #test;
Results in:
+----+------------------------------------+
| id | testvarbinary |
+----+------------------------------------+
| 1 | 0x00 |
| 2 | 0x00 |
| 3 | 0x00 |
| 4 | 0x00000000000000000000000000000000 |
+----+------------------------------------+

There was a feature introduced in SQL Server 2012 that allows NOT Null Columns to be added to a existing table (with a default constraint)
This was to allow not-null to be added to very large tables.
This is restricted to Enterprise Edition and functionally equivalent SKUs which is why you only see this on some instances in your testing.
The way it works is that the existing rows are left NULL until there are next touched and the value is retrieved from metadata.
The metadata itself is fine and can be inspected with
SELECT pc.default_value
FROM tempdb.sys.system_internals_partitions p
JOIN tempdb.sys.system_internals_partition_columns pc
ON p.partition_id = pc.partition_id
WHERE p.object_id = OBJECT_ID('tempdb..#test')
AND default_value IS NOT NULL;
But when the values are read the change to 0x00 happens.
Interestingly - if you change your default to 0x00000000000000000000000000000001
Then all rows get updated with the correct value:
id testvarbinary
1 0x00000000000000000000000000000001
2 0x00000000000000000000000000000001
3 0x00000000000000000000000000000001
4 0x00000000000000000000000000000001
One possible workaround would be to make the default constraint non deterministic (and not possible to cache as a runtime constant) to prevent the online column add. Though you then lose the performance benefits of the feature.
The following default constraint expression avoids the problem
DEFAULT 0x00000000000000000000000000000000 + CAST(LEFT(NEWID(),0) AS varbinary(1))
You should report this as a bug on the uservoice site.

Related

Is there a way to make another value inside ID Primary key? [duplicate]

This question already has answers here:
Reset identity seed after deleting records in SQL Server
(25 answers)
Closed 2 years ago.
i have an primary key who generated itself when i tried to insert some data, but the problem is it will be generated the last one who i deleted before
I wan to make an input when i input the new data the generated id will be 17 not 72 and so on, i'm using SQL SERVER 2008, help :{
...but the problem is it will be generated the last one i deleted before
Do not expose your primary key. It's a bad idea.
Primary keys are internal unique row identifiers. They are not supposed to be sexy or good looking. If you are caring about its value, then it means you somehow want to expose its value to the external world, and that's a really bad idea; if you do this you'll be converting this key into a natural key somewhere else in a different application and that can become an expensive dependency to maintain in the short, medium, and long term.
Solution? If you really care about the format, numbering, and you want to expose the PK, then create a secondary key [column] on the table. This one can be generated automatically, with any value or format you prefer. And you can feel free to expose it to any other application, or even to the end user.
You can set IDENTITY_INSERT ON on the table and insert 17 and corresponding values. Read Identity_insert on MSDN. Also make sure that there should not any conflict occuring in future due to existing identity setup.
In that, you would have to reseed the identity.
You cannot update the identity column. You have to insert it fresh.
Sample code below
create table #table (id int identity(1,1), name varchar(30))
insert into #table
values('A'),('B')
SELECT * FROM #TABLE
SET IDENTITY_INSERT #table ON
insert into #table(id,name) values(8,'C')
SET IDENTITY_INSERT #table OFF
SELECT * FROM #table
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 8 | C |
+----+------+

SQL unique constraint of a max of two entries per user

Is it possible to generate a unique constraint in SQL that will allow a single user (user_id) up to two entries that are enabled (enabled)? An example is as follows
user_id | enabled
------------------
123 | true
123 | true
123 | false
456 | true
The above would be valid, but adding another user_id = 123 and enabled = true would fail because there would be three entries. Additionally adding user_id = 123 and enabled = false would be valid because the table would still satisfy the rule.
You could make it work by adding another boolean column to the UNIQUE or PRIMARY KEY constraint (or UNIQUE index):
CREATE TABLE tbl (
user_id int
, enabled bool
, enabled_first bool DEFAULT true
, PRIMARY KEY (user_id, enabled, enabled_first)
);
enabled_first tags the first of each instance with true. I made it DEFAULT true to allow simple insert for the first enabled per user_id - without mentioning the added enabled_first. An explicit enabled_first = false is required to insert a second instance.
NULL values are excluded automatically by the PK constraint I used. Be aware that a simple UNIQUE constraint still allows NULL values, working around your desired constraint. You would have to define all three columns NOT NULL additionally. See:
Allow null in unique column
db<>fiddle here
Of course, now the two true / false values are different internally, and you need to adjust write operations. This may or may not be acceptable. May even be desirable.
Welcome side-effect: Since the minimum payload (actual data size) is 8 bytes per index tuple, and boolean occupies 1 byte without requiring alignment padding, the index is still the same minimum size as for just (user_id, enabled).
Similar for the table: the added boolean does not increase physical storage. (May not apply for tables with more columns.) See:
Calculating and saving space in PostgreSQL
Is a composite index also good for queries on the first field?
You cannot allow two values of "enabled". But here is a solution that comes close to what you want without using triggers. The idea is to encode the value as numbers and enforce uniqueness on two of the values:
create table t (
user_id int,
enabled_code int,
is_enabled boolean as (enabled_code <> 0),
check (enabled_code in (0, 1, 2))
);
create unique index unq_t_enabled_code_1
on t(user_id, enabled_code)
where enabled_code = 1;
create unique index unq_t_enabled_code_2
on t(user_id, enabled_code)
where enabled_code = 2;
Inserting new values is a bit tricky, because you need to check if the value goes in slot "1" or "2". However, you can use is_enabled as the boolean value for querying.
It has been explained already that a constraint or unique index only cannot enforce the logic that you want.
An alternative approach would be to use a materialized view. The logic is to use window functions to create an additional column in the view that resets every two rows having the same (user_id, enabled). You can then put a unique partial index on that column. Finally, you can create a trigger that refreshes the view everytime a record is inserted or updated, which effectively enforces the unique constraint.
-- table set-up
create table mytable(user_id int, enabled boolean);
-- materialized view set-up
create materialized view myview as
select
user_id,
enabled,
(row_number() over(partition by user_id, enabled) - 1) % 2 rn
from mytable;
-- unique partial index that enforces integrity
create unique index on myview(user_id, rn) where(enabled);
-- trigger code
create or replace function refresh_myview()
returns trigger language plpgsql
as $$
begin
refresh materialized view myview;
return null;
end$$;
create trigger refresh_myview
after insert or update
on mytable for each row
execute procedure refresh_myview();
With this set-up in place, let's insert the initial content:
insert into mytable values
(123, true),
(123, true),
(234, false),
(234, true);
This works, and the content of the view is now:
user_id | enabled | rn
------: | :------ | -:
123 | t | 0
123 | t | 1
234 | f | 0
234 | t | 0
Now if we try to insert a row that violates the constraint, an error is raised, and the insert is rejected.
insert into mytable values(123, true);
-- ERROR: could not create unique index "myview_user_id_rn_idx"
-- DETAIL: Key (user_id, rn)=(123, 0) is duplicated.
-- CONTEXT: SQL statement "refresh materialized view myview"
-- PL/pgSQL function refresh_myview() line 3 at SQL statement
Demo on DB Fiddle

Unknown system variable 'ROWCOUNT' [duplicate]

Is there an easy way to INSERT a row when it does not exist, or to UPDATE if it exists, using one MySQL query?
Use INSERT ... ON DUPLICATE KEY UPDATE. For example:
INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1
I know this is an old question, but the Google lead me here recently so I imagine others come here, too.
#chaos is correct: there is the INSERT ... ON DUPLICATE KEY UPDATE syntax.
However, the original question asked about MySQL specifically, and in MySQL there is the REPLACE INTO ... syntax. IMHO, this command is easier and more straightforward to use for upserts. From the manual:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Note this is not standard SQL. An example from the manual:
CREATE TABLE test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)
mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)
mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)
Edit: Just a fair warning that REPLACE INTO isn't like UPDATE. As the manual says, REPLACE deletes the row if it exists, then inserts a new one. (Note the funny "2 rows affected" in the example above.) That is, it will replace the values of all columns of an existing record (and not merely update some columns.) The behavior of MySQL's REPLACE INTO is much like that of Sqlite's INSERT OR REPLACE INTO. See this question for some workarounds if you only want to update a few columns (and not all columns) if the record already exists.

Why does SQL Server populate new fields in existing rows in some environments and not others?

I am using MS SQL Server 2012. I have this bit of SQL:
alter table SomeTable
add Active bit not null default 1
In some environments the default value is applied to existing rows and in other environments we have to add an update script to set the new field to 1. Naturally I am thinking that the difference is a SQL Server setting but my searches thus far are not suggesting which one. Any suggestions?
Let me know if the values of particular settings are desired.
Edit: In the environments that don't apply the default the existing rows are set to 0, which at least conforms to the NOT NULL.
If you add the column as not null it will be set to the default value for existing rows.
If you add the column as null it will be null despite having a default constraint when added to the table.
For example:
create table SomeTable (id int);
insert into SomeTable values (1);
alter table SomeTable add Active_NotNull bit not null default 1;
alter table SomeTable add Active_Null bit null default 1;
select * from SomeTable;
returns:
+----+----------------+-------------+
| id | Active_NotNull | Active_Null |
+----+----------------+-------------+
| 1 | 1 | NULL |
+----+----------------+-------------+
dbfiddle.uk demo: http://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=c4aeea808684de48097ff44d391c9954
Default value will be applied to existing row to avoid violation of "NOT NULL" constraint.

Auto increment even and odd for two databases for synchronization without affecting auto increment property

Need quick help. I am having my database with bigint auto increment property. I have database on two location's which need to synchronized. As bigint is not good choice for synchronization because of possibility primary key replica on different sites. I can not move on with GUID because for that i need to change my code as well as database which is not possible for me.
Right now i have two location only for database, so i think if can make my primary key auto increment to be always even at one location and to be odd at other location. It can solve my issue in quick manner.
How can i do it using computed column specification or by any other way. For synchronization i am using Microsoft sycn framework.
If i use identity(1,2) A server or identity(2,2) B server after synchronization it disturbs next increment value. For example if at A server max id 3 and at B server current id is 4. After sync max id on A server will be now 4. I want new id on A server should be 5 only but in reality it inserts 6. How can i solve this issue
Here is a very simple solution, but it will work only for two servers. It can't be easily extended for more servers.
The good thing about it is that it doesn't use CHECKIDENT to reseed the tables and you don't need to worry about simultaneously running transactions to get the accurate MAX ID to feed into CHECKIDENT.
Also, MSDN warns that identity property on a column does not guarantee the following:
Consecutive values after server restart or other failures – SQL Server
might cache identity values for performance reasons and some of the
assigned values can be lost during a database failure or server
restart. This can result in gaps in the identity value upon insert. If
gaps are not acceptable then the application should use its own
mechanism to generate key values. Using a sequence generator with the
NOCACHE option can limit the gaps to transactions that are never
committed.
If you choose a solution that is based on reseeding identity using CHECKIDENT you'd better double check that it works correctly in such cases.
Also, to run CHECKIDENT you may need specific permissions:
Caller must own the table, or be a member of the sysadmin fixed server
role, the db_owner fixed database role, or the db_ddladmin fixed
database role.
Solution
My main idea is that on the first server you use IDENTITY(1,1) and on the second server you use IDENTITY(-1,-1). Rather than trying to make IDs odd and even they will be positive and negative.
Here is a script that proves that it works as intended without any extra work.
-- Sample data
CREATE TABLE #T1 (ID bigint IDENTITY(1,1), V1 int);
CREATE TABLE #T2 (ID bigint IDENTITY(-1,-1), V2 int);
INSERT INTO #T1 VALUES (11);
INSERT INTO #T1 VALUES (12);
INSERT INTO #T1 VALUES (13);
INSERT INTO #T1 VALUES (14);
INSERT INTO #T2 VALUES (21);
INSERT INTO #T2 VALUES (22);
INSERT INTO #T2 VALUES (23);
SELECT * FROM #T1;
SELECT * FROM #T2;
We start with this sample data in our tables:
#T1
ID V1
1 11
2 12
3 13
4 14
#T2
ID V2
-1 21
-2 22
-3 23
Perform the sync
-- Insert into T1 new values from T2
SET IDENTITY_INSERT #T1 ON;
MERGE INTO #T1 AS Dst
USING
(
SELECT ID, V2
FROM #T2
) AS Src
ON Dst.ID = Src.ID
WHEN NOT MATCHED BY TARGET
THEN INSERT (ID, V1)
VALUES (Src.ID, Src.V2);
SET IDENTITY_INSERT #T1 OFF;
-- Insert into T2 new values from T1
SET IDENTITY_INSERT #T2 ON;
MERGE INTO #T2 AS Dst
USING
(
SELECT ID, V1
FROM #T1
) AS Src
ON Dst.ID = Src.ID
WHEN NOT MATCHED BY TARGET
THEN INSERT (ID, V2)
VALUES (Src.ID, Src.V1);
SET IDENTITY_INSERT #T2 OFF;
SELECT * FROM #T1;
SELECT * FROM #T2;
Result of the sync - two identical tables
#T1
ID V1
1 11
2 12
3 13
4 14
-1 21
-2 22
-3 23
#T2
ID V2
-1 21
-2 22
-3 23
1 11
2 12
3 13
4 14
Insert more data to check how identity works after the sync
-- Insert more data into T1 and T2
INSERT INTO #T1 VALUES (15);
INSERT INTO #T1 VALUES (16);
INSERT INTO #T2 VALUES (24);
INSERT INTO #T2 VALUES (25);
INSERT INTO #T2 VALUES (26);
SELECT * FROM #T1;
SELECT * FROM #T2;
-- Clean up
DROP TABLE #T1;
DROP TABLE #T2;
Generated identities after the sync
#T1
ID V1
1 11
2 12
3 13
4 14
-1 21
-2 22
-3 23
5 15
6 16
#T2
ID V2
-1 21
-2 22
-3 23
1 11
2 12
3 13
4 14
-4 24
-5 25
-6 26
You can see that new identities in T1 continue to be positive and new identities in T2 continue to be negative.
Big Edit: (Much better) Option 1:
(Additional note: #VladimirBaranov mentioned this in the comments, and I missed it, but here's a fleshing out of how to use a SEQUENCE in this situation anyway)
My original idea is further down this answer, and would still be potentially viable, but I think this newer option will fit the bill exactly for however many servers you need. It was bothering me that I knew there was a right way to do this in TSQL, and I could not remember what it was. My brain finally dredged it up today: SEQUENCE. SQL Server 2012 and 2014 allow you to define a sequence to generate a series of numbers for use in your tables:
CREATE SEQUENCE oddNums
START WITH 1
INCREMENT BY 2;
GO
CREATE SEQUENCE evenNums
START WITH 0
INCREMENT BY 2;
GO
Then instead of AUTO INCREMENTing your PK's, give them a DEFAULT value from the SEQUENCE (these are the tables from the fiddle linked below):
CREATE TABLE oddMirror (
[id] int PRIMARY KEY DEFAULT NEXT VALUE FOR oddNums,
[data] varchar(7)
);
CREATE TABLE evenMirror (
[id] int PRIMARY KEY DEFAULT NEXT VALUE FOR evenNums,
[data] varchar(7)
);
These sequences are totally unaffected by merges, and will continue to generate odd or even numbers forever no matter what the latest PK in the table is.
Here is a SQLFiddle of this in action.
Note that you can't define the column as IDENTITY if you do this (because of the DEFAULT clause), so you will have to be careful about inserting into your id column, but otherwise this should be about as straightforward as it gets.
This could be done with as many servers as you want, just adjust how much each SEQUENCE increments by and where it starts from, but you would have a hard (not impossible) time adding additional servers to the mix once your SEQUENCEs were defined.
Also, here is an MSDN blog that discusses alternative strategies for simulating a SEQUENCE on prior versions of SQL Server.
(Not as good) Option 2:
(Note: this is my original answer) I have been playing with this some this evening, and depending on how you have things set up, I think you could get away with reseeding the table on each server after the sync is done, based on the current highest id in the table. You would just have to do it slightly differently for each server to keep new ids odd on one and even on the other.
So you have:
CREATE TABLE oddMirror
(id INT NOT NULL IDENTITY(1,2),
data NVARCHAR(10))
GO
and
CREATE TABLE evenMirror
(id INT NOT NULL IDENTITY(2,2),
data NVARCHAR(10)
GO
After you sync the two tables, you don't know if the current identity seed is odd or even, so you need to reset it on each table to the correct "next" value for the server. So, on oddMirror:
DECLARE #maxId INT
DECLARE #newSeed INT
SET #maxId = (SELECT MAX(id) FROM oddMirror)
SET #newSeed = (SELECT CASE WHEN #maxId % 2 = 1 THEN #maxId ELSE #maxId -1 END)
DBCC CHECKIDENT('dbo.oddMirror', RESEED, #newSeed)
GO
And an almost identical process on evenMirror:
DECLARE #maxId INT
DECLARE #newSeed INT
SET #maxId = (SELECT MAX(id) FROM evenMirror)
SET #newSeed = (SELECT CASE WHEN #maxId % 2 = 0 THEN #maxId ELSE #maxId -1 END)
DBCC CHECKIDENT('dbo.evenMirror', RESEED, #newSeed)
GO
So basically, on oddMirror we are saying, "Get the current max id. if it's odd, don't change it, but if it's even, back it up by one."
Then do the same thing on 'evenMirror', except check whether the max id is even instead of odd.
So as an example, take this data:
oddMirror
1,"one"
3,"three"
5,"five"
and
evenMirror
2,"two"
4,"four"
6,"six"
8,"eight"
(notice that evenMirror has more rows)
After a sync, each table would look like this:
oddMirror
1,"one"
2,"two"
3,"three"
4,"four"
5,"five"
6,"six"
8,"eight"
--evenMirror looks the same as this now
Running things through the above queries:
MAX(id) on oddMirror is 8. 8 % 2 = 0, so set #newSeed = 8 - 1 = 7, meaning the next row in oddMirror will get id = 9.
MAX(id) on evenMirror is also 8, but the query is slightly different. 8 % x = 0 so set #newSeed = 8, meaning the next row in 'evenMirrorwill getid = 10`
id = 7 will be skipped in this scenario, but I'm guessing that's not a tremendous concern.
If you then queried:
INSERT INTO oddMirror (data) VALUE ("data")
GO
INSERT INTO evenMirror (data) VALUE ("otherData")
GO
Tables would look like this:
oddMirror
1,"one"
2,"two"
3,"three"
4,"four"
5,"five"
6,"six"
8,"eight"
9,"data"
and
evenMirror
1,"one"
2,"two"
3,"three"
4,"four"
5,"five"
6,"six"
8,"eight"
10,"otherData"
This could theoretically be expanded out to accommodate more number of servers by changing what modulo you take and adding additional WHENs to the CASE statement for each possibility, although that would certainly get cumbersome to maintain. But, we already knew that the right solution (GUIDs) is not available here, and if you're reading this far, the next best solution (SEQUENCEs) may not be available, so whatever we come up with is inevitably going to be cumbersome.
The biggest drawback to this approach is that the tables must be locked until the sync process is complete. If a write comes in before sync is complete and ids are reseeded, there will almost certainly be a collision. If the tables are not written to very often, or you are already locking them for syncing, or if you have a significant "dead" spot in your daily cycle (like 3-4 a.m. or something) where this could be done without serious disruption, it may not be that big of a deal, but only you will know how viable this is.
So, your setup may or may not make this possible, but I have been playing with this quite a bit tonight in my sandbox db, and it seems to work well to make sure that new id's are always odd in one db and always even in the other.
An option, have one server set with identity(1,1), and the other set with identity(-1,-1). Identities will not overlap, and copying data from one server to the other would not affect the "next" id or reseeding.
Doesn't work for more than two servers, of course.
You have two source table for inserting to one destination table :
So I suggest you to do these :
[pkId]: Have an identity field in destination table as PK.
[src]: Add an integer -or any other as you want- field and update it from 1st. source data by1and for the 2nd one by2`.
[Id]: You have also a field that comes from sources.
[nId]: Add a bigint field that is null.
Now use this query to have your enumerated Id in nId field:
Update <table>
Set nId = isnull((select count(ti.*) from <table> as ti where ti.pkId < <table>.pkId), 0) + 1
For running this query after any inserts you can use triggers.
I think with this solution you have all data you need.
Edit
some results:
pkId | src | Id | nId before query | nId after query
-----+-----+----+------------------+--------------------
1 | 1 | 1 | null | 1
2 | 2 | 1 | null | 2
3 | 1 | 2 | null | 3
5 | 2 | 2 | null | 4
6 | 2 | 3 | null | 5
8 | 1 | 3 | null | 6
I think that the even/odd approach is making this very hard. Also, as you add rows to each node, you will have page-split issues, especially if your PK is the clustered index.
Are these tables replicated using peer-to-peer replication or are they manually synchronized? The page split issues would come into play if there is replication involved.
Why not use ranges of numbers for each node? 1-X for node 1, and X+1-Y for Node#2? Estimate your row volume and set the ranges so large that overlap won't occur.
Example for BIGINT:
Node 1: 1-200000000000 (200 billion rows)
Node 2: 200000000001-600000000000 (400 billion rows)
Leaving 600000000001 and up for future use. Caveat, the Identity does not have a maximum value, you need to police that manually.
To set the identity value to the correct number use DBCC CHECKIDENT with the RESEED option. This would also work if you're married to the even/odd scenario.
This also have the advantage of not page splitting once per insert, especially if the activity per node is not evenly balanced.