DataTable.PrimaryKey is populated with unique clustered index, not primary key - c#

I have a SQL Server table MyTable with a primary key set for column A and also unique clustered index set for columns B and C.
After this call:
(new SqlDataAdapter(new SqlCommand($"select top 0 * from MyTable", conn))).FillSchema(theDataTable, SchemaType.Mapped);
the theDataTable has its .PrimaryKey set to columns B and C, not A.
Why is this so?

As I've commented, this is actually covered in the documentation FillSchema(DataTable, SchemaType, IDbCommand, CommandBehavior):
FillSchema also configures the PrimaryKey and Constraints properties
according to the following rules:
If one or more primary key columns are returned by the SelectCommand, they are used as the primary key columns for the
DataTable.
If no primary key columns are returned but unique columns are, the unique columns are used as the primary key if, and only if, all the
unique columns are nonnullable. If any of the columns are nullable, a
UniqueConstraint is added to the ConstraintCollection, but the
PrimaryKey property is not set.
If both primary key columns and unique columns are returned, the primary key columns are used as the primary key columns for the
DataTable.
Note that primary keys and unique constraints are added to the
ConstraintCollection according to the preceding rules, but other
constraint types are not added.
If a unique clustered index is defined on a column or columns in a SQL
Server table and the primary key constraint is defined on a separate
set of columns, then the names of the columns in the clustered index
will be returned. To return the name or names of the primary key
columns, use a query hint with the SELECT statement that specifies the
name of the primary key index. For more information about specifying
query hints, see Query Hint (Transact-SQL).
If you do need to get the Primary Key details from .PrimaryKey then you'll need to use a hint as the documentation suggests. Without the DDL (including indexes) of your table though, we won't be able to tell you what the hint would be.

Related

Microsoft Sync Framework unique index error

I use the MS Sync Framework to sync my SQL Server instance with a local SQL CE file to make it possible working offline with my Windows app.
I use GUIDs as keys. On my table I have a unique index on 2 columns: user_id and setting_id:
usersettings table
------------------
id PK -> I also tried it without this column. Same result
user_id FK
setting_id FK
value
Now I do the following:
I create a new record in this table in both databases - SQL Server and SQL CE with the same user_id and setting_id.
This should work and merge the data together since this can happen in real life. But I get an error when syncing saying the unique key constraint led to an error. The key pair already exists in the table.
A duplicate value cannot be inserted into a unique index. [ Table name = user_settings,Constraint name = unique_userid_settingid ]
Why can't MS sync handle that? It should not try to insert the key pair again. It should update the value if needed.
The issue is if you add the same key pair to different copies of the table, they get different IDs (GUIDs) as primary keys in this usersettings table.
As this is simply a many-to-many table between Users and Settings, there is no need to have that ID as a PK (or even a column at all).
Instead, just use a concatenated key of the two FKs e.g.,
CREATE TABLE [dbo].[usersettings](
[user_id] [UNIQUEIDENTIFIER] NOT NULL,
[setting_id] [UNIQUEIDENTIFIER] NOT NULL,
[value] [varchar](50) NOT NULL,
CONSTRAINT [PK_usersettings] PRIMARY KEY CLUSTERED ([user_id] ASC, [setting_id] ASC) );
Of course, include appropriate field settings (e.g., if you use VARCHARs to store the IDs) and relevant FKs.
As the rows inserted should now be identical on the two copies, it should merge fine.
If you must have a single column as a unique identifier for the table, you could make it meaningful e.g.,
the PK (ID) becomes a varchar (72)
it gets filled with CONCAT(user_ID, setting_id)
As the User_ID and Setting_ID are FKs, you should already have them generated so concatenating them should be easy enough.
Do you get the error during sync, then it should appear as a conflict, that you must solve in code.
https://learn.microsoft.com/en-us/previous-versions/sql/synchronization/sync-framework-2.0/bb734542(v=sql.105)
I also see this in the manual: By default, the following objects are not copied to the client database: FOREIGN KEY constraints, UNIQUE constraints, DEFAULT constraints, and the SQL Server ROWGUIDCOL property. This indicates poor support for your scenario
I suggest you remove the unique constraint from the device table.

When creating a table in SQLite C# - Do I need to create an index on the primary key? [duplicate]

When an integer column is marked as a primary key in an SQLite table, should an index be explicitly created for it as well? SQLite does not appear to automatically create an index for a primary key column, but perhaps it indexes it anyway, given its purpose? (I will be searching on that column all the time).
Would the situation be any different for a string primary key?
It does it for you.
INTEGER PRIMARY KEY columns aside, both UNIQUE and PRIMARY KEY
constraints are implemented by creating an index in the database (in
the same way as a "CREATE UNIQUE INDEX" statement would). Such an
index is used like any other index in the database to optimize
queries. As a result, there often no advantage (but significant
overhead) in creating an index on a set of columns that are already
collectively subject to a UNIQUE or PRIMARY KEY constraint.
If an column is marked INTEGER PRIMARY KEY, it's actually around twice as fast as a similar search made by specifying any other PRIMARY KEY or indexed value. This is because:
...all rows within SQLite tables have a 64-bit signed integer key that uniquely identifies the row within its table ... Searching for a record with a specific rowid, or for all records with rowids within a specified range is around twice as fast as a similar search made by specifying any other PRIMARY KEY or indexed value.
With one exception noted below, if a rowid table has a primary key that consists of a single column and the declared type of that column is "INTEGER" in any mixture of upper and lower case, then the column becomes an alias for the rowid.
Such a column is usually referred to as an "integer primary key". A
PRIMARY KEY column only becomes an integer primary key if the declared
type name is exactly "INTEGER". Other integer type names like "INT" or
"BIGINT" or "SHORT INTEGER" or "UNSIGNED INTEGER" causes the primary
key column to behave as an ordinary table column with integer affinity
and a unique index, not as an alias for the rowid.
See: http://www.sqlite.org/lang_createtable.html#rowid
A database will always silently create an index for a unique primary key so it can internally check it is unique efficiently.
Having created it, it will use it when necessary.
It won't, of course, always be clustered, and you specify usually in the schema if you want it to be.
When using
CREATE TABLE data(a INTEGER PRIMARY KEY, b, ...)
the traditional additional (hidden) column rowid won't be there: the column a itself will be the row id.
Indeed, the doc states:
In SQLite, a column with type INTEGER PRIMARY KEY is an alias for the ROWID (except in WITHOUT ROWID tables) which is always a 64-bit signed integer.
and also
if a [...] table has a primary key that consists of a single column and the declared type of that column is "INTEGER" [...], then the column becomes an alias for the rowid.
Since a is the row id, no index is necessary, queries on column a will be fast thanks to the B-tree structure:
The data [...] is stored as a B-Tree structure containing one entry for each table row, using the rowid value as the key.
Note: the [...] part I've not quoted is relative to precisions about differences between normal tables and tables with the WITHOUT ROWID clause, but this is totally out of topic here.

Binary cannot be primary but the only column that doesn't change is binary

I have a simple table with few columns which I'm accessing using Linq2sql. The only column that doesn't change is binary. But when I try to make it the primary column - Linq2sql tells me that:
System.Byte[] is not supported for identity members.
(It means primary. There's no identity in the table.)
And if I don't set any primary column linq2sql tells me that it can't work without a primary key.
And if I set a different column as primary - I can't change that column.
What would be a solution here?
Add a unique id column e.g.
alter table mytable add id int identity (1,1)

How do i assign unique identifier for a record in employee table?

I know it's first std question but someone asked me, but i was unable give him apropriate answer.
There are two tables Employee,Technology having many to many relation saved in employee_technology_rel.Employee table having fields- emp_id (auto_increment),emp_name(varchar),DOB (date) where Technology having fields tech_id(auto_increment),tech_name(varchar)
these two tables allows duplication of names.which unique constraint should i define for allowing unique entry?
You can define the unique entry on table employee_technology_rel,
ALTER TABLE employee_technology_rel
ADD CONSTRAINT emptech_pk PRIMARY KEY (emp_id, tech_id)
// or if you have set a primary key already, you can still define via UNIQUE
ALTER TABLE employee_technology_rel
ADD CONSTRAINT emptech_uq UNIQUE (emp_id, tech_id)
what it does is it only allows unique technology for every employee.
in order for you to have unique emp_name on table Employee as well as unique tech_name on table Technology, you can also alter the table by adding unique constraint
ALTER TABLE Employee ADD CONSTRAINT emp_uq UNIQUE (emp_name)
ALTER TABLE Technology ADD CONSTRAINT tech_uq UNIQUE (tech_name)
You want a composite primary key defined on the two columns in employee_technology_rel: emp_id and tech_id.
Unique Index and Unique Constraint are the same. They achieve same
goal. SQL Performance is same for both.
Add Unique Constraint
ALTER TABLE dbo. ADD CONSTRAINT
UNIQUE NONCLUSTERED ( ) ON
[PRIMARY]
Add Unique Index
CREATE UNIQUE NONCLUSTERED INDEX
ON dbo. ( ) ON
[PRIMARY]
Source sqlauthority.com and msdn from Google search: "SQL server unique index".

Having trouble creating a one to 'zero or one' relationship using Entity Framework

I have two tables:
CREATE TABLE Order (
orderId INTEGER IDENTITY NOT NULL,
PRIMARY KEY (orderId)
)
CREATE TABLE OrderAdditionalDetails (
additionalDetailsId INTEGER IDENTITY NOT NULL,
orderId INTEGER NOT NULL,
PRIMARY KEY (additionalDetailsId),
FOREIGN KEY (orderId) REFERENCES Order(orderId)
)
I have a Foreign key (FK_OrderAdditionalDetails_Order) declared on the OrderAdditionalDetails table, on the orderId field. I also have a 'unique' constraint on the orderId field in the OrderAdditionalDetails table. The idea is that each 'order' will have zero or one entries in the 'OrderAdditionalDetails' table.
This all picked up by the entity framework model file, however when I try to create the Navigation property, it only lets me declare a 1 to many relationship. The error I get is as follows:
Running transformation: Multiplicity is not valid in Role 'OrderAdditionalDetails' in relationship 'FK_OrderAdditionalDetails_Order'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be *.
I'm really not sure what this means - googling the error did not prove helpful. Can anybody shed some light on what I am doing wrong?
In your OrderAdditionalDetails table, remove the additionalDetailsID column and make the orderID the CLUSTERED PRIMARY KEY. Keep the FOREIGN KEY you already have. That is the right way to implement this.
There is not only no value added by the additionalDetailsId column, it makes things worse by taking more space in the table. The orderID is already a sufficient key; you need no secondary artificial key that is nothing but a surrogate for orderID.
Your Foreign Key must be defined as UNIQUE in order to enforce a One-To-Zero-Or-One relationship.
Maybe try something like this:
CREATE TABLE OrderAdditionalDetails (
additionalDetailsId INTEGER IDENTITY NOT NULL,
orderId INTEGER NOT NULL UNIQUE,
PRIMARY KEY (additionalDetailsId),
FOREIGN KEY (orderId) REFERENCES Order(orderId)
)
See Also: Implementing one-to-zero-or-one relation in SQL Server
I was trying to associate a table with a view of itself plus some other fields. (There is a very good reason for this that has nothing to do with the answer)
What cause the same error was there was more than one key field on the view. Even though I had specified the fields involved in the association it wanted both to be the only key fields for a 1 to 1 to work.
I also set the key field to be Distinct in the view, but I did that before I removed the key attribute of other fields, so it may ,or may not, be necessary.

Categories

Resources