How to set a primary key? - sql

SELECT TOP 1000 [LicensePlate]
,[Manufacturer]
,[Model]
,[Colour]
,[Year]
,[EngineSize]
,[Value]
FROM [Cars2].[dbo].[Cartable1]
Above is my layout for a cars table. I am completely new to SQL and was wondering how I would set 'Licence Plate' as the primary key?

First find any duplicates by that column.
SELECT
C.LicensePlate,
AmountDuplicates = COUNT(*)
FROM
Cars2.dbo.Cartable1 AS C
GROUP BY
C.LicensePlate
HAVING
COUNT(*) > 1
If any record shows up, you need to either delete all the duplicates or update their license plates so they don't repeat anymore.
You will also need to check for NULL values and update or delete them (primary key can't be null).
SELECT
C.*
FROM
Cars2.dbo.Cartable1 AS C
WHERE
C.LicensePlate IS NULL
Then you can add the PRIMARY KEY constraint with:
ALTER TABLE Cars2.dbo.Cartable1
ADD CONSTRAINT PK_Cartable1 -- Name of the constraint
PRIMARY KEY (LicensePlate)
You might get an error if LicensePlate can hold NULL values. You can change it with an ALTER TABLE:
ALTER TABLE Cars2.dbo.Cartable1 ALTER COLUMN LicensePlate VARCHAR(20) NOT NULL -- The proper data type
If you already have a primary key defined on that table you will have to drop it and then create your new one (one table can only have 1 primary key constraint at a time). You can check which one is it with the following query:
USE Cars2; -- The database name here
DECLARE #TableName VARCHAR(100) = 'Cartable1'
DECLARE #SchemaName VARCHAR(100) = 'dbo'
SELECT
ColumnName = Col.Column_Name,
ConstraintName = tab.CONSTRAINT_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS Tab
INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS Col ON
Col.Constraint_Name = Tab.Constraint_Name AND
Col.Table_Name = Tab.Table_Name
WHERE
Constraint_Type = 'PRIMARY KEY' AND
Col.Table_Name = #TableName AND
Col.TABLE_SCHEMA = #SchemaName
Once you see the result, you can drop the current primary key with another ALTER TABLE:
ALTER TABLE Cars2.dbo.Cartable1 DROP CONSTRAINT ConstraintNameFromThePreviousQuery

CREATE TABLE Cartable1(
LicensePlate int NOT NULL PRIMARY KEY,
Manufacturer varchar(255) NOT NULL,
Model varchar(255),
Colour varchar(255),
Model varchar(255),
Year int,
EngineSize int,
Value float
);

You do this when you create a table or through an alter table statement:
create table [Cars2].[dbo].[Cartable1] (
LicensePlace varchar(?) primary key,
. . .
);
I recommend adding the primary key when you create the table and before you add any data into it.

If You already have table with data try this ,
ALTER TABLE [Cars2].[dbo].[Cartable1]
ADD CONSTRAINT PRIMARY_KEY_LicensePlate PRIMARY KEY(LicensePlate)

Related

Creating a single table for two different entities

What is an appropriate way to structure the database table for the following scenario?
I'm trying to model an incident report, part of it will be recording whether (as part of the incident) an employee or customer had to receive medical attention. The same details are to be recorded for both. In the paper version of the form and in the interface, it is shown as a single table. The table headings would be:
Person (either employee or customer)
Injured
First aid administered
Hospitalised
Details
We already have separate employee and customer tables which old their personal details. The new table would include the ID, details on whether the person was injured, received first aid, hospitalised and any other additional details.
So I've been pondering on a few possibilities of how this could be structured:
Two separate tables for employee and customer incidents. The two tables will hold mostly the same fields with the exception of the foreign keys for EmployeeID or CustomerID.
A single table that includes all the incident related fields and additional fields for EmployeeID and CustomerID where these are nullable foreign keys to the primary keys of the Employee and Customer table respectively. A constraint to ensure that EmployeeID XOR CustomerID is not null.
Create 3 new tables: one to just hold the incidents, one to link customer ID with an incident and another to link employee ID with an incident - is this too normalised? (assuming I will never have more than customers or employees to record incident details for)
A single table that includes all the incident related fields with a single field to store either the employee ID or customer ID and a type field to specify whether it's employee or customer.
I'm leaning towards option 1, it seems to be the cleanest and should different fields need to be recorded for customers and employees, it's easy to update a single table without affecting the other. I've discounted option 4, I think this is bad design since I'm not able to add a FK constraint to the ID column.
Are there any reasons why I shouldn't go for option 1 or are there better alternatives I should also consider?
I would create "link" tables. And not repeat the DDL for the Incident.
then you have the ability to create a view which would bring together customers and employees with the incident data.
I agree with the previous answer to separate the incident details.
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwIncidents' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwIncidents]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'CustomerToIncidentLink' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[CustomerToIncidentLink]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'EmployeeToIncidentLink' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[EmployeeToIncidentLink]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Incident' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Incident]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' )
BEGIN DROP TABLE [dbo].[Customer]
END
CREATE TABLE [dbo].[Employee] (
[EmployeeUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN)
GO
CREATE TABLE [dbo].[Customer] (
[CustomerUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[CustomerNumber] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Customer ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_CustomerNumber_Unique UNIQUE (CustomerNumber)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[Incident]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[Incident]
END
GO
CREATE TABLE [dbo].[Incident]
(
IncidentUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID()
, IncidentName varchar(24) not null
, CreateDate smalldatetime not null
)
GO
ALTER TABLE dbo.Incident ADD CONSTRAINT PK_Incident PRIMARY KEY NONCLUSTERED (IncidentUUID)
GO
ALTER TABLE [dbo].[Incident] ADD CONSTRAINT CK_IncidentName_Unique UNIQUE (IncidentName)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[EmployeeToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[EmployeeToIncidentLink]
END
GO
CREATE TABLE [dbo].[EmployeeToIncidentLink] (
[LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
[TheEmployeeUUID] [uniqueidentifier] NOT NULL,
[TheIncidentUUID] [uniqueidentifier] NOT NULL
)
GO
ALTER TABLE dbo.EmployeeToIncidentLink ADD CONSTRAINT PK_EmployeeToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToEmployee FOREIGN KEY (TheEmployeeUUID) REFERENCES dbo.Employee (EmployeeUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_EmpUUID_InciUUID UNIQUE (TheEmployeeUUID , TheIncidentUUID)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[CustomerToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[CustomerToIncidentLink]
END
GO
CREATE TABLE [dbo].[CustomerToIncidentLink] (
[LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
[TheCustomerUUID] [uniqueidentifier] NOT NULL,
[TheIncidentUUID] [uniqueidentifier] NOT NULL
)
GO
ALTER TABLE dbo.CustomerToIncidentLink ADD CONSTRAINT PK_CustomerToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToCustomer FOREIGN KEY (TheCustomerUUID) REFERENCES dbo.Customer (CustomerUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_CustomerUUID_InciUUID UNIQUE (TheCustomerUUID , TheIncidentUUID)
GO
CREATE VIEW dbo.vwIncidents
AS
/* combine what is in common with employees and customers for this view */
select e.LastName, e.FirstName, inc.IncidentName
from dbo.Employee e
join
dbo.EmployeeToIncidentLink link on e.EmployeeUUID = link.TheEmployeeUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID
UNION ALL
select c.LastName, c.FirstName, inc.IncidentName
from dbo.Customer c
join
dbo.CustomerToIncidentLink link on c.CustomerUUID = link.TheCustomerUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID
GO
There is another option (I think?)
Create a Person table, (this has info in common with customers and employees) and then create "sub class" tables for customer and employee that has unique to that entity data.
That's a topic unto itself.
See
How do we implement an IS-A Relationship?
"IS A"
or "how to subclass in a database" would be search tips.
I have this example that is close to yours, that does a "subclassing"
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwPersonEmail' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwPersonEmail]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonEmail' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[PersonEmail]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Customer]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonSuperType' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[PersonSuperType]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Department' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Department]
END
GO
CREATE TABLE [dbo].[Department](
[DepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[DepartmentName] [nvarchar](80) NULL,
[CreateDate] [datetime] NOT NULL,
[MyTinyInt] tinyint not null
)
ALTER TABLE dbo.[Department] ADD CONSTRAINT PK_Department PRIMARY KEY NONCLUSTERED ([DepartmentUUID])
GO
ALTER TABLE [dbo].[Department] ADD CONSTRAINT CK_DepartmentName_Unique UNIQUE ([DepartmentName])
GO
CREATE TABLE [dbo].[PersonSuperType] (
[PersonSuperTypeUUID] [uniqueidentifier] not null default NEWSEQUENTIALID(),
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL
)
GO
ALTER TABLE dbo.PersonSuperType ADD CONSTRAINT PK_PersonSuperTypeUUID PRIMARY KEY CLUSTERED (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[Employee] (
[EmployeeUUID] [uniqueidentifier] NOT NULL,
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToPersonSuperType FOREIGN KEY (EmployeeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[Customer] (
[CustomerUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[CustomerNumber] [nvarchar](11) NOT NULL,
[CreateDate] [datetime] NOT NULL,
)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_Customer_CustomerNumber_Unique UNIQUE (CustomerNumber)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT FK_CustomerToPersonSuperType FOREIGN KEY (CustomerUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[PersonEmail] (
[PersonEmailUUID] [uniqueidentifier] NOT NULL,
[PersonSuperTypeUUID] [uniqueidentifier] NOT NULL,
[EmailAddress] [varchar](256) NOT NULL
)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT PK_PersonEmail PRIMARY KEY NONCLUSTERED (PersonEmailUUID)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT CK_PersonEmail_EmailAddress_Unique UNIQUE (EmailAddress)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT FK_PersonEmailToPersonSuperType FOREIGN KEY (PersonSuperTypeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE VIEW dbo.vwPersonEmail
AS
/* combine what is in common with employees and customers for this view */
select per.LastName, per.FirstName, [UniqueIdentifier] = emp.SSN, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Employee emp on per.PersonSuperTypeUUID = emp.EmployeeUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID
UNION ALL
select per.LastName, per.FirstName, [UniqueIdentifier] = cust.CustomerNumber, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Customer cust on per.PersonSuperTypeUUID = cust.CustomerUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID
GO
So now that I think about it, I might lean toward the "subclassing" way..since your two types of people might have alot of common attributes, and a few distinct ones.
If you want only to show information about 2 diferent tables in only one, you could use a View. Here you have an example check it out.
https://www.w3schools.com/sql/sql_view.asp => tutorial
https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/rzatc/rzatcviewmultsql.htm => example
I'd formalize the distinction between the incident and the details.
INCIDENT_HEADER
Customer ID <nullable, fk into the customer table>
Employee ID <nullable, fk into the employee table, which already exsits>
Summary
Date
Status (?)
INCIDENT_DETAIL
DETAIL_TYPE_ID <fk into a type table, it's up next...>
DESCRIPTION
DETAIL_TYPE
ID
DESCRIPTION
DETAIL_TYPE will end up with things like "Injury", "Hospitalized", and "First Aid". You can add more to that table later without touching the details table.
This design lets you add more kinds of details without altering the header table.

INSERT Conflict on Virtual Table SQL

I am having a problem on the INSERT because of a FK reference. The process goes like this:
I create the table Cuentas, and Cuentas_Con_RowNumber
I select from a huge table with over 3 million records. Because some are repeated and I need to store only 1 "cuenta", I made the tempDB. I have to do this, because on the huge db there are many records with the same Cuenta_Nro with different transactions, and I just need one.
I select from the tempDB all the columns but the RowNumber and then insert it into the Cuentas table.
The problem is that the tempDB Pais (country) column is not a FK which references to the Paises (countries) table, and on the original table (Cuentas) it does, therefore, it crashes.
Code:
CREATE TABLE Paises
(
Pais_Id numeric(18,0) PRIMARY KEY NOT NULL,
Pais_Nombre varchar(255) NOT NULL
)
CREATE TABLE Cuentas
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_Moneda varchar(255) DEFAULT 'Dolar',
Cuenta_Tipo numeric(18,0)
FOREIGN KEY REFERENCES Tipo_De_Cuentas(Tipo_De_Cuenta_Id),
Cuenta_PaisOrigen numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_PaisAsignado numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Tarjeta numeric(18, 0)
FOREIGN KEY REFERENCES Tarjetas(Tarjeta_Nro),
Cuenta_Cliente numeric(18, 0)
FOREIGN KEY REFERENCES Clientes(Cliente_Id)
)
CREATE TABLE #Cuentas_Con_RowNumer
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_PaisOrigen numeric(18,0)),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Cliente numeric(18,0),
Cuenta_Tarjeta numeric(18,0),
RowNumber int
)
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
Maestro.Cuenta_Numero, Maestro.Cuenta_Estado, Maestro.Cuenta_Pais_Codigo,
Maestro.Cuenta_Fecha_Creacion, Maestro.Cuenta_Fecha_Cierre, Clientes.Cliente_Id, Maestro.Tarjeta_Numero,
ROW_NUMBER() OVER (PARTITION BY Maestro.Cuenta_Numero ORDER BY Maestro.Cuenta_Numero) AS RowNumber
FROM gd_esquema.Maestra Maestro, dbo.Clientes
WHERE
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre) AS a
WHERE a.RowNumber = '1'
INSERT INTO Cuentas
(
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
)
SELECT
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
FROM #Cuentas_Con_RowNumer
The error message is:
Instrucción INSERT en conflicto con la restricción FOREIGN KEY "FK__Cuentas__Cuenta___24B338F0". El conflicto ha aparecido en la base de datos "GD1C2015", tabla "dbo.Paises", column 'Pais_Id'.
The issue is because Maestro.Cuenta_Pais_Codigo column is being pulled from gd_esquema.Maestra table which in turn is going as Cuenta_PaisOrigen in target table and has a foreign key defined.
There will be some records which are being selected for insert Cuentas table that doesn't have a matching Pais_Id record in dbo.Paises table.
You can add a inner join as below and check the results as :
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
...
FROM gd_esquema.Maestra Maestro
inner join dbo.Clientes on
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre
inner join Paises P on Maestro.Cuenta_Pais_Codigo = P.Pais_Id
) AS a
WHERE a.RowNumber = '1'

SQL Server 2008 select constraints order by primary key

I have the following SQL statement to retrieve drop constraint statements.
SELECT DISTINCT 'ALTER TABLE '+TABLE_NAME+' DROP CONSTRAINT '+CONSTRAINT_NAME AS 'DropConstraintStatement'
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
WHERE TABLE_NAME = 'USER';
The result of this query is:
ALTER TABLE UNITS DROP CONSTRAINT FK_USER_TASK_ID
ALTER TABLE UNITS DROP CONSTRAINT PK_USER
ALTER TABLE UNITS DROP CONSTRAINT UQ_USER_NAME_VERSION
I want to execute these statements within a Java application, hence I need these statements ordered such that the drop primary key constraint is at the last position like:
ALTER TABLE UNITS DROP CONSTRAINT FK_USER_TASK_ID
ALTER TABLE UNITS DROP CONSTRAINT UQ_USER_NAME_VERSION
ALTER TABLE UNITS DROP CONSTRAINT PK_USER
Is there any nice possibility to do this with native SQL?
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE does not hold the necessary information to distinguish between PK and other constraints. If you are sure your PK names start with PK
you could try adding ORDER BY like this:
ORDER BY CASE WHEN CONSTRAINT_NAME LIKE 'PK%' THEN 1 ELSE 0 END
However, I would suggest switching to SQL Server system views for more precise data. sys.key_constraints holds info about primary keys and unique constraints, and sys.foreign_keys about foreign keys.
WITH CTE AS
(
SELECT OBJECT_NAME(parent_object_id) AS TABLE_NAME
, name AS CONSTRAINT_NAME, Type
FROM sys.key_constraints
WHERE parent_object_id = object_id('YourTable')
UNION
SELECT OBJECT_NAME(parent_object_id) AS TABLE_NAME
, name AS CONSTRAINT_NAME, Type
FROM sys.foreign_keys
WHERE parent_object_id = object_id('YourTable')
)
SELECT 'ALTER TABLE '+TABLE_NAME+' DROP CONSTRAINT '+CONSTRAINT_NAME AS 'DropConstraintStatement'
FROM CTE
ORDER BY CASE WHEN Type = 'PK' THEN 1 ELSE 0 END

Changing datatype of a column, which is referenced by other tables

I want to change the datatype of a primary key column in Table A, which is referenced by Table B. The schema is something like-
Table A: (col1A number, col2A...)
Table B: (col1B number, col2B...)
col2B -> col1A
I want to change datatype of col1A from number to varchar. I want that to reflect in Table B also. Is there any simple way to do that?
--
Thanks.
No, there is no simple way to do this. Assuming that both tables have data in them, you'd need to
Add a new VARCHAR2 column to table A
Update A to set the new column equal to TO_CHAR( col1A )
Add a new 'VARCHAR2` column to table B
Update B to set the column equal to TO_CHAR( col2B )
Drop the existing foreign key constraint
Drop the existing primary key constraint
Drop col1A from A
Drop col2B from B
Rename the new columns (if desired) in A & B to col1A and col2B
Create the new primary key constraint
Create the new foreign key constraint
Obviously, that's going to be a rather expensive operation.
This is a proof of concept in T-SQL (SQL Server). Basically, we're changing the primary key's data type from INT to UNIQUEIDENTIFIER (GUID) in table A, which is referenced by a foreign key in table B.
-- ARRANGE
CREATE TABLE A(
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT PK_A PRIMARY KEY (Id)
)
CREATE TABLE B(
[Id] INT IDENTITY(1,1) NOT NULL,
[A_Id] INT NOT NULL,
CONSTRAINT PK_B PRIMARY KEY (Id),
CONSTRAINT FK_B_A FOREIGN KEY (A_Id) REFERENCES A(Id)
)
INSERT A DEFAULT VALUES
DECLARE #A_Id INT
SELECT #A_Id = SCOPE_IDENTITY()
INSERT INTO B VALUES (#A_Id)
INSERT INTO B VALUES (#A_Id)
INSERT INTO B VALUES (#A_Id)
INSERT INTO B VALUES (#A_Id)
INSERT INTO B VALUES (#A_Id)
-- ACT
ALTER TABLE A ADD New_Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()
ALTER TABLE B ADD New_A_Id UNIQUEIDENTIFIER NULL
UPDATE B SET B.New_A_Id = (SELECT A.New_Id FROM A WHERE A.Id = B.A_Id)
ALTER TABLE B DROP FK_B_A
ALTER TABLE B DROP COLUMN A_Id
EXEC sp_RENAME 'B.New_A_Id', 'A_Id', 'COLUMN'
ALTER TABLE A DROP PK_A
ALTER TABLE A DROP COLUMN Id
ALTER TABLE A ADD CONSTRAINT PK_A PRIMARY KEY (New_Id)
EXEC sp_RENAME 'A.New_Id', 'Id', 'COLUMN'
ALTER TABLE B ADD CONSTRAINT FK_B_A FOREIGN KEY (A_Id) REFERENCES A(Id)
-- ASSERT
SELECT * FROM A
SELECt * FROM B

How to insert row in table with foreign key to itself?

I have table that has foreign key for itself. Column parentid is foreign key and it cannot be NULL.
if I doINSERT INTO mytable(name) VALUES('name'), so it says that can't insert NULL to parentid. BUT, what value I can set to it if no row was inserted yet?!
How I can write script that will add row to this table?
Thank you
Remove the NOT NULL constraint, as it is an inappropriate constraint. If you do not have a ParentId then the value is NULL and should be allowed. Creating a dummy row just to have a dummy parentid creates unnecessary dependencies.
A trick: Have a dummy row with a dummy key, say 99999. Insert with this as the FK, and then change the FK to its real value. And do it in a transaction.
Disable the FK in charge.
Then do the insert
Then do an update with the new (generated?) PK-ID into the Self-FK-Field
Then Enable the FK back.
LIke so:
ALTER TABLE [Client] NOCHECK CONSTRAINT [FK_Client_MainClient]
INSERT INTO Client VALUES ...
#ClientID = SCOPE_IDENTITY()
IF #IsMainClient=1
BEGIN
UPDATE [Client]
SET MainClientID = #ClientID
WHERE ClientID = #ClientID
END
ALTER TABLE [Relatie] WITH CHECK CHECK CONSTRAINT [FK_Relatie_Relatie]
How to make a dummy row with both id and parentid equal to -1:
CREATE TABLE mytable(
id int NOT NULL IDENTITY,
parentid int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (parentid) REFERENCES mytable(id)
) ;
SET IDENTITY_INSERT mytable ON ; <-- this allows you to insert the
INSERT INTO mytable(id, parentid) <-- auto incremented identity field
VALUES (-1, -1);
SET IDENTITY_INSERT mytable OFF ;
SELECT * FROM mytable ;
| id | parentid |
| -1 | -1 |
If you have many data from other tables that you want to transfer into this table, you can set the IDENTITY_INSERT variable to ON, insert the data and then set it to OFF again.
But as others said, it might be better to just remove the NOT NULL constraint from the parentid field.
You can alter the column to allow null then set the fk to the new identity and enable not null again.
This should work, though maybe there is a better way
CREATE TABLE mytable
(
id int IDENTITY(1,1) primary key,
name varchar(50) not null,
parentid int not null
)
go
alter table mytable
add constraint FK_mytable_parentid FOREIGN KEY ( parentid ) references mytable(id)
ALTER TABLE mytable alter column parentid int null;
insert into mytable(name)
select 'test'
update mytable
set parentid = SCOPE_IDENTITY()
where id = SCOPE_IDENTITY()
ALTER TABLE mytable alter column parentid int not null;
select * from mytable
drop table mytable
From what I understood you already have id before inserting and you can't insert it because identity field isn't letting you to.
Like you mentioned in your comment:
in 1 table I have the rows 34 'name1'
34, 35 'name2' 34 (id,name,parentid)
and I want to copy them to other table
First table
create table Table1
(
id int not null primary key,
name varchar(20) not null,
parentId int not null
)
insert Table1
values
(34, 'name1', 34),
(35, 'name2', 34)
Second table:
create table Table2
(
id int identity(1, 1) primary key,
name varchar(20) not null,
parentId int not null foreign key references Table2(id)
)
Copying data from the first table to the second one:
set identity_insert Table2 on
insert Table2(id, name, parentId)
select *
from Table1
set identity_insert Table2 on
[Update]
If the second table already has values then:
alter table Table2
add oldId int null
alter table Table2
alter column parentId int null
go
insert Table2(name, oldId)
select name, id
from Table1
update tt3
set parentId = tt2.id
from Table2 tt3
join Table1 tt1 on
tt1.id = tt3.oldId
join Table2 tt2 on
tt1.parentId = tt2.oldId
alter table Table2
drop column oldId
alter table Table2
alter column parentId int not null
Don't reference an IDENTITY column as a self-referencing foreign key. Use an alternative key of the table instead. I guess you are using IDENTITY as a surrogate key but every table ought to have a natural key as well, so the IDENTITY column shouldn't be the only key of your table.