Importing into Gender Field in SQL/SSIS - sql

How would you handle importing only male (m) or female (f) data into a gender field, so that it won't get populated with any potential extraneous source data, in SQL or SSIS?

You can create a column constraint:
CREATE TABLE Persons
(
Id int NOT NULL,
LastName varchar(255),
FirstName varchar(255),
Gender varchar(1),
CONSTRAINT chk_Gender CHECK (Gender ='m' or Gender='f')
)
Insert into Persons values(1,'smith', 'jane', 'f');
insert into Persons values(2,'smith', 'john', SUBSTRING('male', 1, 1));
/* this will fail
INSERT INTO Persons values (3,'foo', 'bar', 'u');
*/
select * FROM Persons;
Working Fiddle

It's trival to add a check constraint, something like:
CREATE TABLE #Test (
GENDER CHAR(1) CONSTRAINT Constraint_Gender CHECK (GENDER IN ('A','B','C'))
)
INSERT INTO #Test VALUES ('A')
INSERT INTO #Test VALUES ('D')
(1 row(s) affected)
Msg 547, Level 16, State 0, Line 9
The INSERT statement conflicted with the CHECK constraint "Constraint_Gender".
However, you should really cater for non-binary genders in a similar manner to facebook etc https://www.facebook.com/facebookdiversity/posts/774221582674346 (hence A, B, C in my example above)

Related

How can I return the top N most recently inserted records from a table? [duplicate]

I have created table like below:
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int
)
And inserted rows like this:
insert into EmployeeDetails values(1, 'A', 'Developer', 3)
insert into EmployeeDetails values(5, 'E', 'CEO', 5)
insert into EmployeeDetails values(2, 'B', 'Developer', 3)
insert into EmployeeDetails values(3, 'C', 'Manager', 4)
insert into EmployeeDetails values(4, 'D', 'S.Manager', 5)
My question is: how can I identify the last inserted row in the table?
Used queries:
select IDENT_CURRENT('EmployeeDetails')
Select SCOPE_IDENTITY()
But I still didn't find the answer.
Replies are always welcome
You have a fundamental misunderstanding of tables in relational databases. They represent unordered sets. So, there is no "last row" in a table. The information on the ordering of rows has to be included when you create the table and/or load data into it.
In SQL Server, the simplest method is an identity column. That is why many tables are defined as:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int
);
You can also add default insertion time columns:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedAt datetime default gettime()
);
However, you can have multiple rows with the same datetime value.
You also can use rowversion like below,if you add a column
CREATE TABLE MyTest (myKey int
,myValue int, RV rowversion);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
select * from mytest order by rv desc
Note:
This always give the last row inserted/Updated
References:
rowversion
Add fields of type datetime with name CreateDate and UpdateDate in your table, when you insert record in your table set their value for getdate()
After that you can run queries:
Select top 10 * from YourTable Order By CreateDate DESC
Or for last updated
Select top 10 * from YourTable Order By UpdateDate DESC
Please find my answer as below. Hope this may help you.
Add one more column to store record creation date/time as below.
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedOn datetime
)
After table creation and inserting records write/execute query (here inner query is used) as below
select
*
from EmployeeDetails
where CreatedOn = (select max(CreatedOn) from EmployeeDetails )

How to create a constraint for conditional unique values?

I am using SQL Server. I have this table:
CREATE TABLE Student
(
ID int PRIMARY KEY,
FirstName varchar(100),
LastName varchar(100),
Active bit;
)
I want to have unique(FirstName, LastName) students only if Active = 1. If they are inactive, unique constraint should not trigger. Any idea?
You can't create a CONSTRAINT for that, however, you can create a filtered unique index:
USE Sandbox;
GO
CREATE TABLE dbo.Student (ID int IDENTITY(1, 1) PRIMARY KEY,
FirstName varchar(100),
LastName varchar(100),
Active bit);
CREATE UNIQUE INDEX UQ_StudentName
ON Student (FirstName,LastName)
WHERE Active = 1;
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 1); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 0); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 0); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 1); --Fails;
GO
UPDATE dbo.Student
SET Active = 1
WHERE ID = 2; --Fails;
GO
SELECT *
FROM dbo.Student;
GO
DROP TABLE dbo.Student;
I however, highly recommend against the thought that names are unique. I (personally) shared my name and date of birth with another person at several places in my youth and businesses that treated names (and date of birth) as unique on their systems were such a head ache for the both of us (there really were places where I (or they) couldn't register without using an abbreviated name because we "already existed").
Create a filtered unique index:
CREATE UNIQUE INDEX UNI_Student_FirstName_LastName ON Student (FirstName, LastName)
WHERE Active = 1

"Invalid Column Name" even though the column is created?

I have created a table :
create table Praktikant(
Pr_id char not null Primary key,
Name varchar(100) not null,
Mbiemri varchar(100) not null,
Gender char(1) not null,
Degree varchar(100) not null,
age int,
check (age >18),
foreign key (Pr_id) references Doctor(Dr_id) on update cascade
)
Inserts:
insert into Praktikant values ('1', 'Kastriot', 'Tusha', 'M', 'Student', 19);
insert into Praktikant values ('2', 'Trim', 'Dalipi', 'M', 'Student', 23);
insert into Praktikant values ('3', 'Elira', 'Rrmoku', 'F', 'Studente', 24);
insert into Praktikant values ('4', 'Qendresa', 'Krasniqi', 'F', 'Studente',20);
Query:
select age
from Praktikant
where age > 23
I don't understand why I get this message:
Msg 207, Level 16, State 1, Line 1
Invalid column name 'age'.
Use this query to get table info:
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Praktikant'
then find your table schema because i suspect that you have two tables with the same name in another schema.
after find schema use this query for select info:
select age
from [schema_name].[Praktikant]
where age > 23
You can use this query to get table columns list to check:
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Praktikant'

INSERT INTO table_name VALUES (value1, value2, value3, ...);How to transfer a data of a single column in a single table row

Hi guys I'm working on a vanilla system where we can add many systems in it with data sets and fields. we can add fields and data of each system at run time without changing the structure of database.
CREATE TABLE Type(
ID int,
Name varchar(255),
PRIMARY KEY (ID)
);
INSERT INTO Type VALUES (1, 'cust_obj_7');
INSERT INTO Type VALUES (2, 'cust_obj_8');
CREATE TABLE Object(
ID int,
Name varchar(255),
Description varchar(255),
TypeID int,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID)
);
INSERT INTO Object VALUES (1, 'First', 'First_desc', 1);
INSERT INTO Object VALUES (2, 'Second', 'Second_desc', 1);
CREATE TABLE TypeFields(
ID int,
Name varchar(255),
NameType varchar(255),
TypeID int,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID)
);
INSERT INTO TypeFields VALUES (1, 'First', 'str', 1);
INSERT INTO TypeFields VALUES (2, 'Seond', 'str', 1);
INSERT INTO TypeFields VALUES (3, 'Third', 'int', 1);
CREATE TABLE FieldsData(
ID int,
ObjectID int,
FieldID int,
FieldName varchar(255),
TypeID int,
value varchar(255),
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID),
FOREIGN KEY (ObjectID ) REFERENCES Object(ID),
FOREIGN KEY (FieldID ) REFERENCES TypeFields(ID)
);
INSERT INTO VALUES (1, 1, 1, 'First', 1, "a");
INSERT INTO VALUES (2, 1, 2, 'Second', 1, "b");
INSERT INTO VALUES (3, 1, 3, 'Third', 1, "120");
INSERT INTO VALUES (4, 2, 1, 'First', 1, "c");
INSERT INTO VALUES (5, 2, 2, 'Second', 1, "d");
INSERT INTO VALUES (6, 2, 3, 'Third', 1, "130");
CREATE TABLE FinalTable(
ObjID int,
ObjName varchar(255),
ObjDesc varchar(255),
First varchar(255),
Second varchar(255),
Third int
);
Data will look like this
Insert Into FinalTable
select *
from object, fieldsdata
where object.iD = fieldsdata.objectiD
Values(object.ID , object.Name, object.Description, ....... );
I want to create a single data set form these tables as finaltable as shown above. I can get all the data using keys but I'm having issue to write that data to a single row from a column of different rows. I'm stuck that how can I achieve this using sql in sas-base.
First, "My custom table" should be a view originating from "Fields data". "Fields data" is a bit of a misnomer because it contains the values of the fields. So in an abstraction that distinction is important for understanding within the framework you are building.
A row in "My custom table" appears to be for projecting TypeID=1. You don't show other TypeID values, but I presume they would be for different custom tables.
The custom tables should really be views, otherwise each object is a potential +1 to a multiplier regarding storage requirements
In your sample image the second row of "My custom table" has ObjID=2, yet shows values from the "Fields data" that correspond to ObjID=2. I will presume a typo.
The "Object types" name is not rendered in the Custom table, thus I would consider it simply a catalog of types.
The design you present is not a normal form yet. Not sure why FieldName is replicated in "Fields data", you have the FieldID that refers to a record with the name. Not sure why TypeID is present in "Fields data" because TypeID is essentially a catalog item selector for the desired projection of the "Fields data"
This kind of design can cause a lot of reinvention and will take huge amounts of time to flesh out for different value types such as dates, value rendering formats, multivalued types, etc...
Regardless, the projection of the values data as an object type to a custom table is essentially a transposition of a join that combines object, type fields, and fields data. SAS SQL does not have a PIVOT operator (such as is found in MS SQL Server). The 'old school' way to pivot in SQL involves aggregating case statements over a by group. Search SO
There are some designs for an 'arbitrarium' that simply kill all the middle men and have a single enormous values monolith with say 20 ID fields, 1,000 numeric fields, 1,000 character fields and 100 date fields and each 'object' is a use-case SQL view against it.
** EDIT - ADDED BELOW **
Added code demonstrating 'old school' pivot:
PROC SQL;
CREATE TABLE Type(
ID int,
Name varchar(255)/*,
PRIMARY KEY (ID)*/
);
INSERT INTO Type VALUES (1, 'cust_obj_7');
INSERT INTO Type VALUES (2, 'cust_obj_8');
CREATE TABLE Object(
ID int,
Name varchar(255),
Description varchar(255),
TypeID int/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID);*/
);
INSERT INTO Object VALUES (1, 'First', 'First_desc', 1);
INSERT INTO Object VALUES (2, 'Second', 'Second_desc', 1);
CREATE TABLE TypeFields(
ID int,
Name varchar(255),
NameType varchar(255),
TypeID int/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID) */
);
INSERT INTO TypeFields VALUES (1, 'First', 'str', 1);
INSERT INTO TypeFields VALUES (2, 'Seond', 'str', 1);
INSERT INTO TypeFields VALUES (3, 'Third', 'int', 1);
CREATE TABLE FieldsData(
ID int,
ObjectID int,
FieldID int,
FieldName varchar(255),
TypeID int,
value varchar(255)/*,
PRIMARY KEY (ID),
FOREIGN KEY (TypeID ) REFERENCES Type(ID),
FOREIGN KEY (ObjectID ) REFERENCES Object(ID),
FOREIGN KEY (FieldID ) REFERENCES TypeFields(ID)*/
);
INSERT INTO FieldsData VALUES (1, 1, 1, 'First', 1, "a");
INSERT INTO FieldsData VALUES (2, 1, 2, 'Second', 1, "b");
INSERT INTO FieldsData VALUES (3, 1, 3, 'Third', 1, "120");
INSERT INTO FieldsData VALUES (4, 2, 1, 'First', 1, "c");
INSERT INTO FieldsData VALUES (5, 2, 2, 'Second', 1, "d");
INSERT INTO FieldsData VALUES (6, 2, 3, 'Third', 1, "130");
CREATE TABLE FinalTable(
ObjID int PRIMARY KEY,
ObjName varchar(255),
ObjDesc varchar(255),
First varchar(255),
Second varchar(255),
Third int
);
create view example_type1_realized as
select
FieldsData.ObjectID as ObjID
, max(Object.Name) as ObjName
, max(Object.Description) as ObjDesc
, max(case when FieldID=1 then Value end) as First
, max(case when FieldID=2 then Value end) as Second
, max(case when FieldID=3 then input(Value,best12.) end) as Third
from FieldsData
join Object
on FieldsData.ObjectID = Object.ID
where TypeID = 1
group by ObjID
;
Now, for each TypeID you will need to construct a code generator that can create the source code wallpaper ... max(case when ... construct. from the TypeFields data.
Here is one way:
* Now a codegener macro that can produce the example realization: ;
%macro realize (TypeID=, out=);
%local wallpaper;
proc sql noprint;
select cat
(
', max(case when FieldID=', cats(ID), ' then '
, case
when NameType='str' then 'Value'
when NameType='int' then 'input(Value,12.)'
else 'cats(Value) || " (' || NameType || ') unhandled"'
end
, ' end)'
, ' as ', Name
) length=32000
into :wallpaper separated by ' '
from TypeFields
where TypeID = &TypeID
;
%put NOTE: wallpaper=%SUPERQ(wallpaper);
create &out as
select
FieldsData.ObjectID as ObjID
, max(Object.Name) as ObjName
, max(Object.Description) as ObjDesc
&wallpaper
from FieldsData
join Object
on FieldsData.ObjectID = Object.ID
group by ObjID
;
quit;
%mend;
options mprint;
%realize(TypeID=1, out=table type1_replicate)
You can modify the codegener so that it will insert rows into an out= instead of creating anew.
You should see that your system is workable but needs alot of attention to become generic. Each FieldType might get format, informat, length, date handling, error handling for out-of-range values for type, field sequence, etc...

Insert values of one table in a database to another table in another database

I would like to take some data from a table from DB1 and insert some of that data to a table in DB2.
How would one proceed to do this?
This is what I've got so far:
CREATE VIEW old_study AS
SELECT *
FROM dblink('dbname=mydb', 'select name,begins,ends from study')
AS t1(name varchar(50), register_start date, register_end date);
/*old_study now contains the data I wanna transfer*/
INSERT INTO studies VALUES (nextval('studiesSequence'),name, '',3, 0, register_start, register_end)
SELECT name, register_start, register_end from old_study;
This is how my table in DB2 looks:
CREATE TABLE studies(
id int8 PRIMARY KEY NOT NULL,
name_string VARCHAR(255) NOT NULL,
description VARCHAR(255),
field int8 REFERENCES options_table(id) NOT NULL,
is_active INTEGER NOT NULL,
register_start DATE NOT NULL,
register_end DATE NOT NULL
);
You should include the column names in both the insert and select:
insert into vip_employees(name, age, occupation)
select name, age, occupation
from employees;
However, your data structure is suspect. Either you should use a flag in employees to identify the "VIP employees". Or you should have a primary key in employees and use this primary key in vip_employees to refer to employees. Copying over the data fields is rarely the right thing to do, especially for columns such as age which are going to change over time. Speaking of that, you normally derive age from the date of birth, rather than storing it directly in a table.
INSERT INTO studies
(
id
,name_string
,description
,field
,is_active
,register_start
,register_end
)
SELECT nextval('studiesSequence')
,NAME
,''
,3
,0
,register_start
,register_end
FROM dblink('dbname=mydb', 'select name,begins,ends from study')
AS t1(NAME VARCHAR(50), register_start DATE, register_end DATE);
You can directly insert values that retured by dblink()(that means no need to create a view)
Loop and cursor are weapons of last resort. Try to avoid them. You probably want INSERT INTO ... SELECT:
INSERT INTO x(x, y, z)
SELECT x, y, z
FROM t;
SqlFiddleDemo
EDIT:
INSERT INTO vip_employees(name, age, occupation) -- your column list may vary
SELECT name, age, occupation
FROM employees;
Your syntax is wrong. You cannot have both, a values clause for constant values and a select clause for a query in your INSERT statement.
You'd have to select constant values in your query:
insert into studies
(
id,
name_string,
description,
field,
is_active,
register_start,
register_end
)
select
studiesSequence.nextval,
name,
'Test',
null,
0,
register_start,
register_end
from old_study;