How to force Microsoft Database Project generate ALTER statement for primary key constraint instead of creating temp table? - sql

I have following script for LoginLogo table:
CREATE TABLE [LoginLogo] (
[LoginLogoId] INT IDENTITY (1, 1) NOT NULL,
[LoginId] INT NOT NULL,
[LogoNm] NVARCHAR(255) NULL,
CONSTRAINT [PK_LoginLogo_LoginLogoId] PRIMARY KEY CLUSTERED ([LoginId] ASC),
CONSTRAINT [FK_LoginLogo_LoginId] FOREIGN KEY ([LoginId])
REFERENCES [Login] ([LoginId])
);
GO
CREATE NONCLUSTERED INDEX [IF_LoginLogo_LoginId]
ON [LoginLogo]([LoginId] ASC)
ON [INDX];
I need to change Primary Key Constraint, so I've just changed one line, please see below the change:
CONSTRAINT [PK_LoginLogo_LoginLogoId] PRIMARY KEY CLUSTERED ([LoginLogoId] ASC),
Database project perfectly build changed code, but when it generates database update statement it generates temp table instead of simple ALTER statement. See below generated script:
CREATE TABLE [tmp_ms_xx_LoginLogo] (
[LoginLogoId] INT IDENTITY (1, 1) NOT NULL,
[LoginId] INT NOT NULL,
[LogoNm] NVARCHAR (255) NULL,
CONSTRAINT [tmp_ms_xx_constraint_PK_LoginLogo_LoginLogoId1]
PRIMARY KEY CLUSTERED ([LoginLogoId] ASC)
);
IF EXISTS (SELECT TOP 1 1
FROM [apps].[LoginLogo])
BEGIN
SET IDENTITY_INSERT [apps].[tmp_ms_xx_LoginLogo] ON;
INSERT INTO [apps].[tmp_ms_xx_LoginLogo] ([LoginLogoId], [LoginId], [LogoNm])
SELECT [LoginLogoId],
[LoginId],
[LogoNm],
FROM [LoginLogo]
ORDER BY [LoginLogoId] ASC;
SET IDENTITY_INSERT [tmp_ms_xx_LoginLogo] OFF;
END
DROP TABLE [LoginLogo];
EXECUTE sp_rename N'[tmp_ms_xx_LoginLogo]', N'LoginLogo';
EXECUTE sp_rename N'[tmp_ms_xx_constraint_PK_LoginLogo_LoginLogoId1]',
N'PK_LoginLogo_LoginLogoId', N'OBJECT';
Is it possible to tell Database project to generate ALTER statement instead of creating temp table? How can I force Microsoft Database Project to do that?

Bearing in mind that if you change the clustered index of a table, the table will be rebuilt regardless of whether the script does ALTER TABLE or the SSDT-generated stuff with temp tables, the usual way to solve these problems is to do the ALTER ahead of time
Meaning, you need a script, often referred to as a pre-pre-deploy script (pre-deploy won't work, as it is run post-comparison) that makes the expensive change, so that when the comparison is run the change has already occurred, and hence doesn't get repeated by the dacpac deployment.
This script needs to be run as part of your deployment, before you do any of the sqlpackage stuff. You can specify the change as alter table in this script.
In this particular instance, where the table is going to be rebuilt either way, I can't see it making a great deal of difference to the overall deployment time.

Related

sql server executing update it takes more time

I have two tables (UserTable and UserProfile) and the Structure:
create table userTable(
id_user int identity(1,1) primary key ,
Name varchar(300) not null ,
Email varchar(500) not null ,
PasswordUser varchar(700) not null,
userType int ,
constraint usertype_fk foreign key(userType) REFERENCES userType(id_type)
on delete set null
)
and userPtrofile:
create table UserProfile(
id_profile int identity(1,1) primary key ,
ClientCmpName varchar(300) null,
Clientaddress varchar(500) null,
phone varchar(50) null,
descriptionClient varchar(400) null,
img image null,
messageClient text ,
fk_user int ,
constraint fkuser foreign key(fk_user) references userTable(id_user)
on delete cascade
)
I am using SQL Server 2008.
The problem is that when I update records the executing load without executing
this is sample query:
update UserProfile set messageClient=N'010383772' where fk_user=2;
screenshot
If your concern is performance for this query:
update UserProfile
set messageClient = N'010383772'
where fk_user = 2;
Then an index will be very helpful:
create index idx_UserProfile_fkuser on UserProfile(fk_user);
This should make the query almost instantaneous.
Note: indexes can slow down inserts and other operations. This is usually not a big issue, and having indexes on foreign key columns is common.
Dumb question, why are you trying to do an update based on a [userType] value ?
update UserProfile set messageClient=N'010383772' where fk_user=2;
Don't you want to update this value on one specific [UserProfile] based on its ID (which is a Primary Key, so would be much faster)
UPDATE [UserProfile]
SET [messageClient]='010383772'
WHERE id_profile=2;
Perhaps the performance problem is due to your UPDATE attempting to update all of your [UserProfile] records with this particular UserType value...?
Or I'm missing the point of what you're trying to do (and how many records you're attempting to update).
Maybe you have alredy started a transaction (BEGIN TRANSACTION) on the table in another process (maybe another query editor page) and until you don't stop that transaction the table would not be available for updates.
Check the variable select ##trancount, or try do rollback the updates you have already made (ROLLBACK TRANSACTION).
Also check if other tables can be update without issues.
Is the query ever executed? It rather seems like a deadlock. You should
open the activity monoitor and check if your query is blocked by some process.
In that case, you should kill the blocking query.
Thank you for trying to help me
my problem fixed the problem was another query editor page because i worked with asp.net and another page i use the same record to update the same record when i stop the asp.net project then query was success

Microsoft SQL - Cannot delete a table, "preparing update script" forever

I am using Visual Studio 2015 and have a data connection to an SQL Database on Azure. I can update things just fine but now I need to delete an entire table altogether and it is stuck at "Preparing update script..." forever. How do I remove the table? It does not have any relations with other tables or anything.
Can you please use SQL Server Management Studio for that? Sometimes, i have the same problem with the VS Explorer, and changing to the SSMS almost always is the solution.
If your SQL Azure is not V12 yet, you can do it from the SQL Azure Silverlight portal (clicking on the Manage button on the SQL Azure dasbhoard), but it is not very viable solution.
If that is the helpful answer, please mark it as a helpful or as the answer. Thanks!
This happens when there is a conflict in your database. (I don't have any article reference/s, this is just from my own experience)
For example, you have a stored procedure like this:
INSERT INTO dbo.Employee_Image
(user_image,
file_extension,
employee_id
)
VALUES
(#user_image,
#file_extension,
#FK_Employee_Image_To_Employee_Table
)
And a table like this:
CREATE TABLE [dbo].[Employee_Image] (
[user_image_id] INT IDENTITY (1, 1) NOT NULL,
[employee_id] INT NULL,
[user_image] VARBINARY (MAX) NULL,
[file_extension] VARCHAR (12) NULL,
PRIMARY KEY CLUSTERED ([user_image_id] ASC),
CONSTRAINT [AK_Employee_Image_employee_id] UNIQUE NONCLUSTERED ([employee_id] ASC),
CONSTRAINT [FK_Employee_Image_To_Employee_Table] FOREIGN KEY ([employee_id]) REFERENCES [dbo].[Employee] ([employee_id])
);
If you remove some of the columns (e.g. the file_extension) like this (and try to update):
CREATE TABLE [dbo].[Employee_Image] (
[user_image_id] INT IDENTITY (1, 1) NOT NULL,
[employee_id] INT NULL,
[user_image] VARBINARY (MAX) NULL,
PRIMARY KEY CLUSTERED ([user_image_id] ASC),
CONSTRAINT [AK_Employee_Image_employee_id] UNIQUE NONCLUSTERED ([employee_id] ASC),
CONSTRAINT [FK_Employee_Image_To_Employee_Table] FOREIGN KEY ([employee_id]) REFERENCES [dbo].[Employee] ([employee_id])
);
The "Preparing Update Script" is going to load like FOREVER. But if you also remove the file_extension column in your stored procedure like this (then the "Preparing Update Script" is going to complete fast):
INSERT INTO dbo.Employee_Image
(user_image,
employee_id
)
VALUES
(#user_image,
#FK_Employee_Image_To_Employee_Table
)

Sql Server create table queries

I am using Sql Server Migration assistant to migrate my DB from MySql to SQL Server and in the process learning Sql Server.
The following is the create table syntax for the autogenerated schema.
CREATE TABLE [dbo].[TABLE1] (
[COLUMN1] BIGINT IDENTITY (131556, 1) NOT NULL,
[COLUMN2] INT CONSTRAINT [DF__TABLE_1__PRD_I__24E777C3] DEFAULT ((0)) NULL,
[COLUMN3] INT CONSTRAINT [DF__TABLE1__PROMO__2AA05119] DEFAULT ((0)) NULL,
CONSTRAINT [PK_TABLE1] PRIMARY KEY CLUSTERED ([COLUMN1] ASC)
);
GO
CREATE NONCLUSTERED INDEX [COLUMN3]
ON [dbo].[TABLE1]([COLUMN3] ASC);
GO
EXECUTE sp_addextendedproperty #name = N'MS_SSMA_SOURCE', #value = N'TABLE1',
#level0type = N'SCHEMA', #level0name = N'dbo', #level1type = N'TABLE',
#level1name = N'TABLE1';
I am trying to understand and cleanup the schema.Can someone please help with the following (naive) questions?
Why should the primary key (COLUMN1) specified as a PRIMARY KEY CLUSTERED?
In the original MySql table, COLUMN3 indexed. Is NONCLUSTERED INDEX the equivalent for Sql Server? What is the meaning of
CREATE NONCLUSTERED INDEX [COLUMN3]
ON [dbo].[TABLE1]([COLUMN3] ASC);
I did not understand the following:
EXECUTE sp_addextendedproperty #name = N'MS_SSMA_SOURCE', #value = N'TABLE1',
#level0type = N'SCHEMA', #level0name = N'dbo', #level1type = N'TABLE',
#level1name = N'TABLE1';
Can someone explain what it does?
Is the above create table syntax the minimal syntax to achieve what it does?
I have 131555 rows in my MySql table. Should I be specifying IDENTITY (131556, 1) to start auto increment of key from 131556 after I migrate data?
1.Why should the primary key (COLUMN1) specified as a "PRIMARY KEY CLUSTERED"?
It is generally best for every SQL Server table to have a clustered index, and only one clustered index is allowed per table because the b-tree leaf nodes of the clustered index are the actual data pages. The index supporting the primary key is often the best candidate but you can make the PK non-clustered and have different index as the clustered one if that's advantageous for your particular situation. For example, if your queries of most often range searches on COLUMN3 instead of queries that select or join by COLUMN1, the COLUMN3 index might be a better choice along with a NONCLUSTERED primary key.
2.In the original MySql table, COLUMN3 indexed. Is NONCLUSTERED INDEX the equivalent for Sql Server? What is the meaning of
A non-clustered index is also a b-tree index, allowing rows to be located by the index key more efficiently than a table scan.
3.I did not understand the following:
EXECUTE sp_addextendedproperty #name = N'MS_SSMA_SOURCE', #value =
N'TABLE1', #level0type = N'SCHEMA', #level0name = N'dbo', #level1type
= N'TABLE', #level1name = N'TABLE1';
Can someone explain what it does?
SQL Server has an extended property feature that allows you to attach meta-data to database objects. In this case, SSMA added an extended property to indicate the table was created by the tool.
4.Is the above create table syntax the minimal syntax to achieve what it does?
No. For example, one could omit the constraint names and SQL Server would generate a name automatically. However, the best practice is to explicitly name constraints to facilitate subsequent DDL changes and so that the purpose is self-documenting. Personally, I'd name the default constraints like DF_TABLENAME_COLUMNNAME.
5.I have 131555 rows in my MySql table. Should I be specifying IDENTITY (131556, 1) to start auto increment of key from 131556 after
I migrate data?
If you were to create the table with IDENTITY(1,1) and then insert rows with the IDENTITY INSERT ON option, SQL Server will automatically adjust the next IDENTITY according to the highest value inserted. I don't know much about SSMA but it looks like SSMA already did that for you.
1 and 2. You should probably read this description of the differences between a clustered and non-clustered index: http://msdn.microsoft.com/en-au/library/ms190457.aspx. In short there can be only one clustered index on a table and it defines the sort order for data in the table. You can have many non-clustered indexes on a table.
SQL Server allows you to add extended properties to objects - see here for details: http://technet.microsoft.com/en-us/library/ms190243%28v=sql.105%29.aspx. Basically they are for storing metadata about the object - a description for the table for example, or an input mask for a column.
Here's the full syntax for creating tables: http://msdn.microsoft.com/en-AU/library/ms174979.aspx. I note that your example is creating the table and adding some default constraints. You could rewrite this as
CREATE TABLE [dbo].[TABLE1]
(
[COLUMN1] BIGINT IDENTITY (131556, 1) NOT NULL,
[COLUMN2] INT DEFAULT ((0)) NULL,
[COLUMN3] INT NULL DEFAULT (0),
CONSTRAINT [PK_TABLE1] PRIMARY KEY CLUSTERED ([COLUMN1] ASC)
);
It really depends on whether you want to retain your existing key values, which I would assume you do. If so you should insert the data with
SET IDENTITY_INSERT yourTable ON
Read about identity columns here: http://msdn.microsoft.com/en-us/library/ms186775.aspx

SQL Server 2005: Nullable Foreign Key Constraint

I have a foreign key constraint between tables Sessions and Users. Specifically, Sessions.UID = Users.ID. Sometimes, I want Sessions.UID to be null. Can this be allowed? Any time I try to do this, I get an FK Constraint Violation.
Specifically, I'm inserting a row into Sessions via LINQ. I set the Session.User = null; and I get this error:
An attempt was made to remove a relationship between a User and a Session. However, one of the relationship's foreign keys (Session.UID) cannot be set to null.
However, when I remove the line that nulls the User property, I get this error on my SubmitChanges line:
Value cannot be null.
Parameter name: cons
None of my tables have a field called 'cons', nor is it in my 5,500-line DataContext.designer.cs file, nor is it in the QuickWatch for any of the related objects, so I have no idea what 'cons' is.
In the Database, Session.UID is a nullable int field and User.ID is a non-nullable int. I want to record sessions that may or may not have a UID, and I'd rather do it without disabling constraint on that FK relationship. Is there a way to do this?
I seemed to remember creating a nullable FK before, so I whipped up a quick test. As you can see below, it is definitely doable (tested on MSSQL 2005).
Script the relevant parts of your tables and constraints and post them so we can troubleshoot further.
CREATE DATABASE [NullableFKTest]
GO
USE [NullableFKTest]
GO
CREATE TABLE OneTable
(
OneId [int] NOT NULL,
CONSTRAINT [PK_OneTable] PRIMARY KEY CLUSTERED
(
[OneId] ASC
)
)
CREATE TABLE ManyTable (ManyId [int] IDENTITY(1,1) NOT NULL, OneId [int] NULL)
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ManyTable_OneTable]') AND parent_object_id = OBJECT_ID(N'[dbo].[ManyTable]') )
ALTER TABLE [dbo].[ManyTable] WITH CHECK ADD CONSTRAINT [FK_ManyTable_OneTable] FOREIGN KEY([OneId])
REFERENCES [dbo].[OneTable] ([OneId])
GO
--let's get a value in here
insert into OneTable(OneId) values(1)
select* from OneTable
--let's try creating a valid relationship to the FK table OneTable
insert into ManyTable(OneId) values (1) --fine
--now, let's try NULL
insert into ManyTable(OneId) values (NULL) --also fine
--how about a non-existent OneTable entry?
insert into ManyTable(OneId) values (5) --BOOM! - FK violation
select* from ManyTable
--1, 1
--2, NULL
--cleanup
ALTER TABLE ManyTable DROP CONSTRAINT FK_ManyTable_OneTable
GO
drop TABLE OneTable
GO
drop TABLE ManyTable
GO
USE [Master]
GO
DROP DATABASE NullableFKTest

Constraint for only one record marked as default

How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?
The constraint is not table scope, but one default per set of rows, specified by a FormID.
Use a unique filtered index
On SQL Server 2008 or higher you can simply use a unique filtered index
CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
ON TableName(FormID)
WHERE isDefault = 1
Where the table is
CREATE TABLE TableName(
FormID INT NOT NULL,
isDefault BIT NOT NULL
)
For example if you try to insert many rows with the same FormID and isDefault set to 1 you will have this error:
Cannot insert duplicate key row in object 'dbo.TableName' with unique
index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).
Source: http://technet.microsoft.com/en-us/library/cc280372.aspx
Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.
CREATE VIEW form_defaults
AS
SELECT FormID
FROM whatever
WHERE isDefault = 1
GO
CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
GO
But the serious relational folks will tell you this information should just be in another table.
CREATE TABLE form
FormID int NOT NULL PRIMARY KEY
DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)
From a normalization perspective, this would be an inefficient way of storing a single fact.
I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.
CREATE TABLE [dbo].[Foo](
[Id] [int] NOT NULL,
CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
(
[Id] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DefaultSettings](
[DefaultFoo] [int] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
REFERENCES [dbo].[Foo] ([Id])
GO
ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
GO
You could use an insert/update trigger.
Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.
CREATE VIEW vOnlyOneDefault
AS
SELECT 1 as Lock
FROM <underlying table>
WHERE Default = 1
GO
CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
GO
You'll need to have the right ANSI settings turned on for this.
I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.
You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:
CREATE
UNIQUE
INDEX only_one_default
ON my_table
( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )
This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.
The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.
--drop table dev.defaultAddress;
--drop table dev.addresses;
--drop table dev.people;
CREATE TABLE [dev].[people](
[Id] [int] identity primary key,
name char(20)
)
GO
CREATE TABLE [dev].[Addresses](
id int identity primary key,
peopleId int foreign key references dev.people(id),
address varchar(100)
) ON [PRIMARY]
GO
CREATE TABLE [dev].[defaultAddress](
id int identity primary key,
peopleId int foreign key references dev.people(id),
addressesId int foreign key references dev.addresses(id))
go
create unique index defaultAddress on dev.defaultAddress (peopleId)
go
create unique index idx_addr_id_person on dev.addresses(peopleid,id);
go
ALTER TABLE dev.defaultAddress
ADD CONSTRAINT FK_Def_People_Address
FOREIGN KEY(peopleID, addressesID)
REFERENCES dev.Addresses(peopleId, id)
go
insert into dev.people (name)
select 'Bill' union
select 'John' union
select 'Harry'
insert into dev.Addresses (peopleid, address)
select 1, '123 someplace' union
select 1,'work place' union
select 2,'home address' union
select 3,'some address'
insert into dev.defaultaddress (peopleId, addressesid)
select 1,1 union
select 2,3
-- so two home addresses are default now
-- try adding another default address to Bill and you get an error
select * from dev.people
join dev.addresses on people.id = addresses.peopleid
left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
insert into dev.defaultaddress (peopleId, addressesId)
select 1,2
GO
You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1
EDIT oops, needs to be <=
Create table mytable(id1 int, defaultX bit not null default(0))
go
create Function dbo.fx_DefaultExists()
returns int as
Begin
Declare #Ret int
Set #ret = 0
Select #ret = count(1) from mytable
Where defaultX = 1
Return #ret
End
GO
Alter table mytable add
CONSTRAINT [CHK_DEFAULT_SET] CHECK
(([dbo].fx_DefaultExists()<=(1)))
GO
Insert into mytable (id1, defaultX) values (1,1)
Insert into mytable (id1, defaultX) values (2,1)
This is a fairly complex process that cannot be handled through a simple constraint.
We do this through a trigger. However before you write the trigger you need to be able to answer several things:
do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?
You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).
You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
adding a record with no default and it is the first record for that customer
adding a record with a default and it is the first record for that customer
adding a record with no default and it is the not the first record for that customer
adding a record with a default and it is the not the first record for that customer
Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
Updating a record to remove the default
Deleting the record with the deafult
Deleting a record without the default
Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes
#Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:
ALTER proc [dbo].[cpForm_UpdateLinkedReport]
#reportLinkId int,
#defaultYN bit,
#linkName nvarchar(150)
as
if #defaultYN = 1
begin
declare #formId int, #configId int
select #formId = FormID, #configId = ConfigID from csReportLink where ReportLinkID = #reportLinkId
update csReportLink set DefaultYN = 0 where isnull(ConfigID, #configId) = #configId and FormID = #formId
end
update
csReportLink
set
DefaultYN = #defaultYN,
LinkName = #linkName
where
ReportLinkID = #reportLinkId