SQL Server Database Project in Visual Studio - how to structure for new database - sql-server-data-tools

I want to create a SQL Server database project where a new database is created. Here is the structure of my project :
SQL Server Database Project Structure
Basically, I want 4 tables, so I have added 4 .sql scripts for them.
CREATE TABLE [dbo].[MovieActors]
(
[Id] INT NOT NULL PRIMARY KEY,
[ActorID] INT NOT NULL,
[MovieID] INT NOT NULL
)
CREATE TABLE [dbo].[Actors]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL,
[Bio] NVARCHAR(MAX) NULL,
[Sex] NCHAR(10) NOT NULL,
[DOB] DATE NULL
)
CREATE TABLE [dbo].[Movies]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL,
[Year of Release] SMALLINT NULL,
[PLOT] NVARCHAR(MAX) NULL,
[Poster] NVARCHAR(MAX) NULL,
[ProducerId] int FOREIGN KEY REFERENCES Producers(Id)
)
CREATE TABLE [dbo].[Producers]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL,
[Bio] NVARCHAR(MAX) NULL,
[Sex] NCHAR(10) NULL,
[DOB] DATE NULL
)
And I have also added pre-deployment (for deleting existing data) and post-deployment scripts (for seeding initial data).
Pre-Deployment:
DROP TABLE [dbo].MovieActors
DROP TABLE [dbo].Movies
DROP TABLE dbo.Actors
DROP TABLE dbo.Producers
Post-Deployment:
INSERT INTO dbo.Actors (Id, Name, Sex)
VALUES (1, 'Actor1', 'MALE')
INSERT INTO dbo.Producers (Id, Name, Sex)
VALUES (1, 'Producer1', 'MALE')
INSERT INTO dbo.Movies (Id, Name, ProducerId)
VALUES (1, 'Movie1', 1)
INSERT INTO dbo.MovieActors (Id, MovieID, ActorID)
VALUES (1, 1, 1)
But everytime I am building the project it does not get deployed - only showing build succeeded
Moreover, where is the database creation script.
When I right clicked on publish and chose option to generate script , only pre and post deployment scripts were in the main script. -
Right Click Project -> Publish option
This is the script that gets generated -
/*
Deployment script for MoviesDatabase
This code was generated by a tool.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
*/
GO
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
GO
:setvar DatabaseName "MoviesDatabase"
:setvar DefaultFilePrefix "MoviesDatabase"
:setvar DefaultDataPath "C:\Users\viiye\AppData\Local\Microsoft\VisualStudio\SSDT"
:setvar DefaultLogPath "C:\Users\viiye\AppData\Local\Microsoft\VisualStudio\SSDT"
GO
:on error exit
GO
/*
Detect SQLCMD mode and disable script execution if SQLCMD mode is not supported.
To re-enable the script after enabling SQLCMD mode, execute the following:
SET NOEXEC OFF;
*/
:setvar __IsSqlCmdEnabled "True"
GO
IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'
BEGIN
PRINT N'SQLCMD mode must be enabled to successfully execute this script.';
SET NOEXEC ON;
END
GO
USE [$(DatabaseName)];
GO
/*
Pre-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be executed before the build script.
Use SQLCMD syntax to include a file in the pre-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the pre-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
Drop table [dbo].MovieActors
Drop table [dbo].Movies
Drop table dbo.Actors
Drop table dbo.Producers
GO
GO
/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be appended to the build script.
Use SQLCMD syntax to include a file in the post-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the post-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
INSERT INTO dbo.Actors (Id,Name,Sex)
values (1,'Actor1','MALE')
INSERT INTO dbo.Producers (Id,Name,Sex)
values (1,'Producer1','MALE')
INSERT INTO dbo.Movies (Id,Name,ProducerId)
values (1,'Movie1',1)
Insert into dbo.MovieActors (Id,MovieID,ActorID)
values (1,1,1)
GO
GO
PRINT N'Update complete.';
GO
As can be seen , the create tables script are not there in this script which is used for publish .Why? and is this the correct way to go about requirement where I need to create tables from scratch?

This is are the simplified steps how the project is published:
Project is built and DACPAC file is the output of this step
DACPAC is compared with the destination database and the publish script is generated
Publish script is executed against the destination database
The problem in your case is that at the time when the 2nd step is executed the tables existed at the destination database, so their creation was not included to the publish script. Pre deployment script is executed at the step 3!
Basically what you need to do is not to drop tables. Just TRUNCATE them in pre script and populate in the post. Or simply use MERGE statements in the post script. You can use generate-sql-merge procedure that would generate MERGE statement for needed table.

Related

Can't store other language data in nvarchar column

I am using SQL Server 2008.
This is my Table definition.
create table myTable (nid int identity(1,1),content nvarchar(max));
when I execute these two queries
insert into myTable(content)values(N'हिंदी में परीक्षण');
update myTable set content=N'हिंदी में परीक्षण' where nid=1;
the other language data is inserted/updated in the table. I want to do the same in a stored procedure. This is the definition of my stored procedure.
create proc myProc
#nid int,
#content nvarchar(max)
as
begin
update myTable set content=#content where nid=#nid;
end
it just doesn't work the column is updated with ????????????? value. What should I do. I tried to do this
update myTable set content=N''+#content where nid=#nid;
But this doesn't work as well. Please Help.
I forgot to tell one thing
exec myProc 1,N'हिंदी में परीक्षण'
this does work of course it does the problem is i send data from an asp .net web application where i use this syntax.
public void myProcCall()
{
dbcommand = db.GetStoredProcCommand("myProc", nid, content);
ds = db.ExecuteDataSet(dbcommand);
}
So when I send other language content from the web application the value is updated as ??????????. Do I have to make some changes in my asp .net code.
This will work
EXEC myProc 1, N'हिं में पदी रीक्षण'
This won't
EXEC myProc 1, 'हिं में पदी रीक्षण'
Ergo, the parameter is sent as non-unicode
You need to ensure that the code that populate the parameter sends unicode

Add constraint to existing SQLite table

I'm using SQLite, which doesn't support adding a constraint to an existing table.
So I can't do something like this (just as an example):
ALTER TABLE [Customer]
ADD CONSTRAINT specify_either_phone_or_email
CHECK (([Phone] IS NOT NULL) OR ([Email] IS NOT NULL));
Are there any workarounds for this scenario?
I know:
I can add a constraint for a new table, but it isn't new (and it's generated by my ORM, EF Core)
I can do a "table rebuild" (rename table, create new one, copy old data, drop temp table) but that seems really complex
Ideas
Can I somehow make a copy of the table into a new table, with some schema changes?
Or "get" the schema somehow, and edit it in a SQL script, then add a table with that schema?
To make a copy of a table with some schema changes, you have to do the creation and the copying manually:
BEGIN;
CREATE TABLE Customer_new (
[...],
CHECK ([...])
);
INSERT INTO Customer_new SELECT * FROM Customer;
DROP TABLE Customer;
ALTER TABLE Customer_new RENAME TO Customer;
COMMIT;
To read the schema, execute .schema Customer in the sqlite3 command-line shell.
This gives you the CREATE TABLE statement, which you can edit and execute.
To change the table in place, you can use a backdoor.
First, read the actual table definition (this is the same as what you would get from .schema):
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'Customer';
Add your CHECK constraint to that string, then enable write access to sqlite_master with PRAGMA writable_schema=1; and write your new table definition into it:
UPDATE sqlite_master SET sql='...' WHERE type='table' AND name='Customer';
Then reopen the database.
WARNING: This works only for changes that do not change the on-disk format of the table. If you do make any change that changes the record format (such as adding/removing fields, or modifying the rowid, or adding a constraint that needs an internal index), your database will blow up horribly.

override default script for initialization of flyway metadata table

I'm working with the Microsoft Parallel Data Warehouse appliance and attempting to use flyway to handle table migrations in that environment. The issue I'm running into is that the default script for establishing the schema_version table fails.
Here is the default script as far as I can tell that is being executed upon calling baseline().
CREATE TABLE [dbo].[dbresult_migration] (
[installed_rank] INT NOT NULL,
[version] NVARCHAR(50),
[description] NVARCHAR(200),
[type] NVARCHAR(20) NOT NULL,
[script] NVARCHAR(1000) NOT NULL,
[checksum] INT,
[installed_by] NVARCHAR(100) NOT NULL,
[installed_on] DATETIME NOT NULL DEFAULT GETDATE(),
[execution_time] INT NOT NULL,
[success] BIT NOT NULL
);
ALTER TABLE [dbo].[dbresult_migration] ADD CONSTRAINT [dbresult_migration_pk] PRIMARY KEY ([installed_rank]);
CREATE INDEX [dbresult_migration_s_idx] ON [dbo].[dbresult_migration] ([success]);
Specifically the Microsoft Parallel Data Warehouse (MS PDW or APS as it is now known) doesn't support expressions with default constraints.
Msg 104338, Level 16, State 1, Line 1
An expression cannot be used with a default constraint. Specify only constants for a default constraint.
Which causes an error when GETDATE() is used as the default for the installed_on column.
The ALTER TABLE statement will also fail as PRIMARY KEYs and INDICES are managed differently in the environment.
Is there a way to override the default initialization script for the schema_version?
UPDATE
Further investigation reveals that the next failure occurs when attempting to insert records into the schema_version table. Specifically the current implementation attempts to identify the current user based on a call to dbSupport.getCurrentUserFunction(). For SQL Server this function is SUSER_SNAME(). While this function is available on both the standard SQL Server and the Parallel Data Warehouse the current implementation of the Parallel Data Warehouse does not allow for function calls within the values portion of an insert statement. As such, the following error is returned:
Insert values statement can contain only constant literal values or variable references.
When the query that is attempted is logged as:
INSERT INTO [dbo].[dbresult_migration] ([installed_rank],[version],[description],[type],[script],[checksum],[installed_by],[execution_time],[success]) VALUES (#P0, #P1, #P2, #P3, #P4, #P5, SUSER_SNAME(), #P6, #P7)
UPDATE 2
I now have a fork of flyway-core that correctly identifies if you are connecting to SQL Server vs SQL Server parallel data warehouse. Another issue that I have identified is that SQL Server PDW does not allow DDL within transactions and so an attempt to baseline fails as this appears to be attempted from within a transaction template. Ultimately this is evolving from a question of understanding how to modify an initialization script to a need for support of a new database platform. I've submitted this as a new issue on the flyway repo on github here.

SQLite - Trying to read a file with SQL which contains text with special characters causes strange symbols

I am trying to create a SQL script that can be used to generate a database with a set of data, but once I try to read the script in SQLite, special characters(specifically n with tilde) becomes unreadable by humans. Here is an example of a script with the issue:
create table if not exists person(
id integer primary key not null, --auto increment key
name text NOT NULL
);
begin transaction;
insert into person(name) values ('señor');
end transaction;
Running the Query "SELECT * FROM person;" returns the following result:
1|se├▒or
My class requires that I am able to show special symbols within the sqlite command line app. If I copy and paste the insert command into the sqlite console, then the value will be displayed properly.

Entity framework - history table

I have the following 2 tables defined in a SQL Server database:
create table Project
(
Id int,
Name varchar(100)
IdIdentity int
)
create table ProjectHistory
(
Id int,
Name varchar(100)
IdIdentity int,
DtChange datetime
)
When I updated "Project" I would like to insert new record to table ProjectHistory with setting DtChange to actual date.
I use Entity Framework 4.1. Can you suggest me some way how this can be accomplished?
There is possibility change sql that generate Entity Framework when saving changes.
The conventional way would be to use an update trigger on the project table.
CREATE TRIGGER trgProjectUpdate
ON Project
AFTER UPDATE
AS
BEGIN
insert ProjectHistory (id, name, dtchange)
select id, name, GETDATE() from deleted
END

Resources