rows that exclude each other in create table statement - sql

I have to create a table, with either first name and last name of a person, or a name of an organization. There has to be exactly one of them. For example one row of the table is -
first_name last_name organization
---------- --------- ------------
John Smith null
or another row can be -
first_name last_name organization
---------- --------- --------------------
null null HappyStrawberry inc.
Is there a way to define this in SQL language? Or should I just define all three columns being able to get null values?

Your situation is a classical example of what some ER dialects call "entity subtyping".
You have an entity called "Person" (or "Party" or something of that ilk), and you have two ditinct sub-entities called "NaturalPerson" and "LegalPerson", respectively.
The canonical way to model ER entity subtypes in a relational database is using three tables : one for the "Person" entity with all columns that are "common" for both NaturalPerson and LegalPerson (i.e. that exist for Persons, regardless of their type), and one per identified sub-entity holding all the columns that pertain to that sub-entity in particular.
You can read more on this in Fabian Pascal, "Practical Issues in Database Management".

You could use a check constraint, like:
create table YourTable (
col1 varchar(50)
, col2 varchar(50)
, col3 varchar(50)
, constraint TheConstraint check ( 1 =
case when col1 is null then 1 else 0 end +
case when col2 is null then 1 else 0 end +
case when col3 is null then 1 else 0 end )
)
Another way is to add a type column (EAV method):
create table YourTable (
type varchar(10) check (type in ('FirstName', 'LastName', 'Organisztion')
, value varchar(50))
insert YourTable ('LastName', 'Obama')
insert YourTable ('FirstName', 'Barrack')
insert YourTable ('Orginazation', 'White House')

You can do this using a constraint:
CREATE TABLE [dbo].[Contact](
[first_name] [varchar](50) NULL,
[last_name] [varchar](50) NULL,
[organization] [varchar](50) NULL,
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Contact] WITH CHECK ADD CONSTRAINT [CK_Contact] CHECK (([first_name] IS NOT NULL OR [last_name] IS NOT NULL OR [organization] IS NOT NULL))
GO
ALTER TABLE [dbo].[Contact] CHECK CONSTRAINT [CK_Contact]
GO
The CK_Contact constraint ensures that at least one value was entered.

Related

Generate unique id in SQL Server

How can I create a table with custom ID like 22/00/00001 with a sequence? Sorry I'm a newbie with databases. All help will be appreciated thank you!
I am an intern at a hospital. I have to rewrite a database with SQL Server, I have a problem with specific ID numbers. It must be in year/month/id00001 format, for example 11/22/02586. And each department must have its own patient counter. Any help will be appreciated thanks!.
Example:
CREATE SEQUENCE MySequence
AS INT
START WITH 1
INCREMENT BY 1;
GO
-- Create a new table called 'PATIENT' in schema 'dbo'
-- Drop the table if it already exists
IF OBJECT_ID('dbo.PATIENT', 'U') IS NOT NULL
DROP TABLE dbo.PATIENT
GO
-- Create the table in the specified schema
CREATE TABLE dbo.PATIENT
(
NUM_PAT [VARCHAR] (20) NOT NULL
PRIMARY KEY
CONSTRAINT [DF_PATIENT_ID_PATIENT]
DEFAULT FORMAT ((NEXT VALUE FOR MySequence), '22/00/00000#'), -- primary key column
NOM_PAT [VARCHAR](50) NOT NULL,
PREN_PAT [VARCHAR](50) NOT NULL,
DN_PAT [DATE] NOT NULL,
-- specify more columns here
);
GO
-- Insert rows into table 'PATIENT'
INSERT INTO PATIENT ([NOM_PAT], [PREN_PAT], [DN_PAT])
VALUES ('fred', 'alves', '25/11/1990'),
('alvaldo', 'merlin', '11/09/1985');
-- add more rows here
GO
I'm checking your request, I think you can aproach in two way, a way is define a table where you will save the patient id and a column with counter to generate your custom id
Example
Table name like PatientCounter
PatientID, PatientCounter
1 1
2 125
Or in table patient add a column Counter, I prefer the thing separeted, but this also is a option, then in the query you could do something like that.
DECLARE #PatientId as int
DECLARE #PatientCount as int
SET #PatientId = 21
SET #PatientCount = 1
SELECT
CAST(FORMAT(GETDATE(),'yy') as nvarchar(4)) + '/' +
CAST(MONTH(getDATE()) as nvarchar(4)) + '/' +
CAST(#PatientId as nvarchar(10)) +
CAST(REPLICATE('0', 5 - LEN(#PatientCount + 1)) + RTrim(#PatientCount + 1) as nvarchar(50)) as MyCustomId
The result
MyCustomId
22/11/2100002
And after confirming that your application has consumed this custom id, update the counter in the table.
UPDATE PatientTable SET PatientCount = PatientCount + 1 WHERE PatientID = #PatientId
Best Regards

Creating and populating a table in T-SQL

I'm new to T-SQL and trying to learn how to create a script in T-SQL to create and populate a table(StaffData).The StaffData is defined as below:
staffid – integer primary key, identity starting at 1, increments by 1
managerid – int, allows nulls, pointer to another record in managertable
name – string of 50 characters
salary – money
What can I do to generate table and fill it with set of data..?
Here's the correct SQL. I've tested it (just spotted that you want managerId nullable - I've added this):
it uses better conventions for your table and column names (you shouldn't be using 'data' in table names - we know it contains data)
it names your primary key constraints, which is better practice - you can do something similar for the FK constraint if you want, I've just done it inline
it uses 'USE' and 'GO' statements to ensure you're creating things on the right database (critical when you're working on big production systems).
it uses nvarchar columns - you need these to reliably store data from international character sets (e.g the manager has a Russian name)
I'm using nvarchar(max) as you can't be sure that a name will only be 50 characters. Use nvarchar(50) if you must, but database space isn't usually a big deal.
You need to create the Manager table first, as your Staff table depends on it:
USE [yourDatabaseName] -- you don't need the square brackets, but they don't hurt
-- Create ManagerTable
CREATE TABLE Manager
(
id int IDENTITY(1,1),
name nvarchar(max),
CONSTRAINT pk_manager PRIMARY KEY (id)
)
CREATE TABLE Staff
(
id int IDENTITY(1,1),
name nvarchar(max),
salary money,
managerId int FOREIGN KEY REFERENCES Manager(id) NULL,
CONSTRAINT pk_staff PRIMARY KEY (id)
)
--To populate Manager table:
INSERT INTO [Manager]
(
-- id column value is auto-generated
name
)
VALUES
(
'John Doe'
)
--To populate Staff table:
INSERT INTO [Staff]
(
-- id column value is auto-generated
name, salary, managerId
)
VALUES
(
'Jane Doe', 60000, 1
)
GO
To create the two database tables:
-- Create StaffData
CREATE TABLE StaffData
(
staffid int PRIMARY KEY IDENTITY,
managerid int
)
-- Create ManagerTable
CREATE TABLE ManagerTable
(
managerid int,
name varchar(50),
salary money
)
To populate StaffData table:
INSERT INTO [StaffData]
(
--staffid - this column value is auto-generated
[managerid]
)
VALUES
(
-- staffid - int
12345 -- managerid - int
)
To populate ManagerTable table:
INSERT INTO [ManagerTable]
(
[managerid],
[name],
[salary]
)
VALUES
(
12345, -- managerid - int
'Juan Dela Cruz', -- name - varchar
15000 -- salary - money
)
To select the data if i understand you in your word Pointer here is the query using INNER JOIN joining the two tables using their managerid
SELECT *
FROM [StaffData]
INNER JOIN [ManagerTable]
ON [StaffData].managerid = [ManagerTable].managerid

How To Insert 2 Values in 2 columns and rest null values in rest columns without using Create Table Statement

Please Check this Sample Sql fiddle:http://www.sqlfiddle.com/#!3/f59ae.
In this way only i want output.first 2 columns Should contain values that can be anything
and rest columns should contain Hello values without considering Create Table statement.
I want to write a query that will insert 2 values into 2 columns and Hello into all other columns.
Suppose I have 100 columns then I want 10 and 20 values to be inserted into col1 and col2 and Hello into all other 98 columns.
Likewise if I have 200 columns then I want 10 and 20 values to be inserted into col1 and col2 and Hello into the other 198 columns.
I have written a query which but I thought it's a basic query so I am not writing here. So downvoters please consider that.
How to write this query???
You can do this by just adding the Default constraint to column's which you don't want to insert values explicitly. I hope #Manish Pant's answer should help you to do that.
Based on your comments you want do this only by using query. So you need to use Dynamic sql to do this.
Simple Demo
Schema
CREATE TABLE [dbo].[Test](
[id] [int] IDENTITY(1,1) NOT NULL,
[Country] [varchar](100) NULL,
[State] [varchar](100) NULL,
[City] [varchar](100) NULL,
[Population (in Millions)] [varchar](100) NULL
)
Declare a variable to hold the Dynamic sql
DECLARE #cl_val NVARCHAR(max)='Insert into Test('
Pull all the columns from sys.columns view and filter the identity column
SELECT #cl_val += Quotename(NAME) + ','
FROM sys.columns
WHERE Object_name(object_id) = 'Test'
AND is_identity <> 1
ORDER BY NAME
SELECT #cl_val = LEFT(#cl_val, Len(#cl_val)-1) + ') values (' -- Remove the trailing comma
Here add the values only to the column in case statement which you are explicitly passing value in else part add the default value
SELECT #cl_val += CASE
WHEN NAME ='City' THEN '''A'''
WHEN NAME='country' THEN '''c'''
ELSE '''Hello'''
END + ','
FROM sys.columns
WHERE Object_name(object_id) = 'Test'
AND is_identity <> 1
ORDER BY NAME
SELECT #cl_val = LEFT(#cl_val, Len(#cl_val)-1) + ')' -- Remove the trailing comma
--PRINT #cl_val
EXEC Sp_executesql #cl_val
select * from test
Result
id Country State City Population (in Millions)
-- ------- ----- ---- ------------------------
1 c Hello A Hello
If All other columns are set as Nullable then into your Insert statement you can write statement By without considering your Nullable fields.
Suppose for example your Table named Student with properties is:
Student ::
Name,
RollNo,
OptionalField_1,
OptionalField_2,
OptionalField_3
where columns with OptionalField are Nullble fields.
In this case you can write your Query simply as ::
INSERT INTO Student (Name,RollNo) VALUES ('MyName',12);
So this will make an ENtry with two column values & all remaining as Nullable.
For your better understandings you can refer :: http://www.w3schools.com/sql/sql_insert.asp
You can use this for your query:
create table mytable(
col1 varchar not null,
col2 varchar not null,
col3 varchar not null default 'Hello',
col4 varchar not null default 'Hello',
col5 varchar not null default 'Hello',
so on...... );
insert into mytable(col1,col2) values('10','20');

Implementing an Aliases table (self-referencing many-to-many)

I am trying to model an Alias relationship. That is, several records in my person table may represent the same actual person. I don't care who the "Primary" person is. All Person records would carry equal weight.
I have implemented this in the past with the two tables you see below.
------------- ------------
| Person | | Alias |
|-----------| |----------|
| PersonID | | AliasID |
| LastName | | PersonID |
| FirstName | ------------
-------------
Here is some sample data:
Person (1, 'Joseph', 'Smith')
Person (2, 'Jane', 'Doe')
Person (3, 'Joe', 'Smith')
Person (4, 'Joey', 'Smith')
Alias(1, 1)
Alias(1, 3)
Alias(1, 4)
I suppose I could move the AliasID to the Person table since there is a 1-to-1 relationship between the PersonID fields. However, I may want to add additional fields to the Alias table (like Sequence number, etc.) at some point in the future.
Is there a better way to model this than what I have here?
This is how I would do it.
--DROP TABLE [dbo].[Alias]
GO
--DROP TABLE [dbo].[RealPerson]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[RealPerson]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[RealPerson]
END
GO
CREATE TABLE [dbo].[RealPerson]
(
RealPersonUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID()
, CreateDate smalldatetime default CURRENT_TIMESTAMP
, MyCompanyFriendlyUniqueIdentifier varchar(128) not null
)
GO
ALTER TABLE dbo.RealPerson ADD CONSTRAINT PK_RealPerson
PRIMARY KEY NONCLUSTERED (RealPersonUUID)
GO
ALTER TABLE [dbo].[RealPerson]
ADD CONSTRAINT CK_MyCompanyFriendlyUniqueIdentifier_Unique UNIQUE (MyCompanyFriendlyUniqueIdentifier)
GO
GRANT SELECT , INSERT, UPDATE, DELETE ON [dbo].[RealPerson] TO public
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[Alias]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE [dbo].[Alias]
END
GO
CREATE TABLE [dbo].[Alias]
(
AliasUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID()
, RealPersonUUID [UNIQUEIDENTIFIER] NOT NULL
, CreateDate smalldatetime default CURRENT_TIMESTAMP
, LastName varchar(128) not null
, FirstName varchar(128) not null
, PriorityRank smallint not null
)
GO
ALTER TABLE dbo.Alias ADD CONSTRAINT PK_Alias
PRIMARY KEY NONCLUSTERED (AliasUUID)
GO
ALTER TABLE [dbo].[Alias]
ADD CONSTRAINT FK_AliasToRealPerson
FOREIGN KEY (RealPersonUUID) REFERENCES dbo.RealPerson (RealPersonUUID)
GO
ALTER TABLE [dbo].[Alias]
ADD CONSTRAINT CK_RealPersonUUID_PriorityRank_Unique UNIQUE (RealPersonUUID,PriorityRank)
GO
ALTER TABLE [dbo].[Alias]
ADD CONSTRAINT CK_PriorityRank_Range CHECK (PriorityRank >= 0 AND PriorityRank < 33)
GO
if exists (select * from dbo.sysindexes where name = N'IX_Alias_RealPersonUUID' and id = object_id(N'[dbo].[Alias]'))
DROP INDEX [dbo].[Alias].[IX_Alias_RealPersonUUID]
GO
CREATE INDEX [IX_Alias_RealPersonUUID] ON [dbo].[Alias]([RealPersonUUID])
GO
GRANT SELECT , INSERT, UPDATE, DELETE ON [dbo].[Alias] TO public
GO
INSERT INTO dbo.RealPerson ( RealPersonUUID , MyCompanyFriendlyUniqueIdentifier )
select '11111111-1111-1111-1111-111111111111' , 'ABC'
union all select '22222222-2222-2222-2222-222222222222' , 'DEF'
INSERT INTO dbo.[Alias] ( RealPersonUUID , LastName, FirstName , PriorityRank)
select '11111111-1111-1111-1111-111111111111' , 'Smith' , 'Joseph' , 0
union all select '11111111-1111-1111-1111-111111111111' , 'Smith' , 'Joey' , 1
union all select '11111111-1111-1111-1111-111111111111' , 'Smith' , 'Joe' , 2
union all select '11111111-1111-1111-1111-111111111111' , 'Smith' , 'Jo' , 3
union all select '22222222-2222-2222-2222-222222222222' , 'Doe' , 'Jane' , 0
select 'Main Identity' as X, * from dbo.RealPerson rp join dbo.[Alias] al on rp.RealPersonUUID = al.RealPersonUUID where al.PriorityRank = 0
select 'All Identities' as X, * from dbo.RealPerson rp join dbo.[Alias] al on rp.RealPersonUUID = al.RealPersonUUID
select 'Aliai Only' as X, * from dbo.RealPerson rp join dbo.[Alias] al on rp.RealPersonUUID = al.RealPersonUUID where al.PriorityRank > 0
First, you should identify your entities. Clearly you have a person and each person will have their own identity. They are unique and should allways be kept as such. Then you have Alias's They should be in their own table with a one to many relationship. This should be enfrced with primary keys, forgien keys, indexes for quick lookup where appropriate. Each table need a clustered index also for performance. You should then use stored procedures to return or update the tables. I've intentionally used certain word, because if you google them, you will get lots of good information on what you need to do.

Add a SQL XOR Constraint between two nullable FK's

I'd like to define a constraint between two nullable FK's in a table where if one is null the other needs a value, but both can't be null and both can't have values. Logic is the derived table inherits data from the either of the FK tables to determine its type. Also, for fun bonus points, is this a bad idea?
One way to achieve it is to simply write down what "exclusive OR" actually means:
CHECK (
(FK1 IS NOT NULL AND FK2 IS NULL)
OR (FK1 IS NULL AND FK2 IS NOT NULL)
)
However, if you have many FKs, the above method can quickly become unwieldy, in which case you can do something like this:
CHECK (
1 = (
(CASE WHEN FK1 IS NULL THEN 0 ELSE 1 END)
+ (CASE WHEN FK2 IS NULL THEN 0 ELSE 1 END)
+ (CASE WHEN FK3 IS NULL THEN 0 ELSE 1 END)
+ (CASE WHEN FK4 IS NULL THEN 0 ELSE 1 END)
...
)
)
BTW, there are legitimate uses for that pattern, for example this one (albeit not applicable to MS SQL Server due to the lack of deferred constraints). Whether it is legitimate in your particular case, I can't judge based on the information you provided so far.
You can use check constraint:
create table #t (
a int,
b int);
alter table #t add constraint c1
check ( coalesce(a, b) is not null and a*b is null );
insert into #t values ( 1,null);
insert into #t values ( null ,null);
Running:
The INSERT statement conflicted with the CHECK constraint "c1".
Alternate way is to define this check constraint in a procedure. Before you insert a record in the derived table, the constraint should be satisfied. Else insert fails or returns an error.