SET datatype set in SQL Server - sql

While creating a table I have to use the datatype SET, but it looks like there is no datatype SET in SQL Server. I was looking on the Microsoft's website and those are the datatypes that it supports: http://msdn.microsoft.com/en-us/library/ms187752.aspx
Which one should I use to replace the SET?
I have used SET in MySQL database like this:
CREATE TABLE IF NOT EXISTS `configurations` (
`index` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`configDuration` int(5) NOT NULL,
`configDurationPerspective` set('list_this_day','list_remaining') NOT NULL,
PRIMARY KEY (`index`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
And then when I insert data into the table it looks like this:
INSERT INTO 'configurations' (index, user_id, configDuration, configDurationPerspective) VALUES (1, 1, 2, 'list_this_day');
Never mind the quotes. Something messed up while pasting the code.
Now I want to do the same thing, but in SQL Server.

You'd either have to use separate bit fields (one column with bit datatype per value) or you'd pack the values into a column with a integer datatype. If you'd use integer you'd have to use t-sql bitwise operators to read and write the values.
If you use bitwise operators you'll only get one column
The create table statement should look like this:
CREATE TABLE configurations(
[index] int NOT NULL IDENTITY (1,1) PRIMARY KEY,
user_id int NOT NULL,
configDuration int NOT NULL,
configDurationPerspective int NOT NULL,
)
And then you'd have to insert values that are possible to bitmask like 1,2,4,8,16,32 into configDurationPerspective
INSERT INTO 'configurations' (index, user_id, configDuration, configDurationPerspective) VALUES (1, 1, 2, 'list_this_day');
would translate to
INSERT INTO 'configurations' (index, user_id, configDuration, configDurationPerspective) VALUES (1, 1, 2, 1);
And
INSERT INTO 'configurations' (index, user_id, configDuration, configDurationPerspective) VALUES (1, 1, 2, 'list_remaining');
would translate to
INSERT INTO 'configurations' (index, user_id, configDuration, configDurationPerspective) VALUES (1, 1, 2, 2);
and selecting could look like:
select [index], configDuration,
case when configDurationPerspective & 1 > 0 then 'list_this_day' else '' end
+ case when configDurationPerspective & 2 > 0 then 'list_remaining' else '' end as configDurationPerspective
from configurations

The list of basic types in MS SQL Server does not support the same. But what we have are constraints and user types. In this question you can see how MySQL enum is solved
SQL Server equivalent to MySQL enum data type?
And you can also observe user types (I've seen that they were used for the similar purpose)
http://msdn.microsoft.com/en-us/library/ms175007.aspx
But as the most typical solution to this issue, we were (on our projects) using some "CodeList/StaticList" table and referencing it by Primary key (int, shortint, tinyint)

Related

Securing values for other tables from enumerable table in SQL Server database

English is not my native language, so I might have misused words Enumerator and Enumerable in this context. Please get a feel for what I'm trying to say and correct me if I'm wrong.
I'm looking into not having tables for each enumerator I need in my database.
I "don't want" to add tables for (examples:) service duration type, user type, currency type, etc. and add relations for each of them.
Instead of a table for each of them which values will probably not change a lot, and for which I'd have to create relationships with other tables, I'm looking into having just 2 tables called Enumerator (eg: user type, currency...) and Enumerable (eg: for user type -> manager, ceo, delivery guy... and for currency -> euro, dollar, pound...).
Though here's the kicker. If I implement it like that, I'm loosing the rigidity of the foreign key relationships -> I can't accidentally insert a row in users table that will have a user type of some currency or service duration type, or something else.
Is there another way to resolve the issue of having so many enumerators and enumerables with the benefit of having that rigidity of the foreign key and with the benefit of having all of them in just those 2 tables?
Best I can think of is to create a trigger for BEFORE UPDATE and BEFORE INSERT to check if (for example) the column type of user table is using the id of the enumerable table that belongs to the correct enumerator.
This is a short example in SQL
CREATE TABLE [dbo].[Enumerator]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] VARCHAR(50)
)
CREATE TABLE [dbo].[Enumerable]
(
[Id] INT NOT NULL PRIMARY KEY,
[EnumeratorId] INT NOT NULL FOREIGN KEY REFERENCES Enumerator(Id),
[Name] VARCHAR(50)
)
INSERT INTO Enumerator (Id, Name)
VALUES (1, 'UserType'),
(2, 'ServiceType');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- UserType
VALUES (1, 1, 'CEO'),
(2, 1, 'Manager'),
(3, 1, 'DeliveryGuy');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- ServiceDurationType
VALUES (4, 2, 'Daily'),
(5, 2, 'Weekly'),
(6, 2, 'Monthly');
CREATE TABLE [dbo].[User]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
CREATE TABLE [dbo].[Service]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
The questions are:
Is it viable to resolve enumerators and enumerables with 2 tables and with before update and before insert triggers, or is it more trouble than it's worth?
Is there a better way to resolve this other than using before update and before insert triggers?
Is there a better way to resolve enumerators and enumerables that is not using 2 tables and triggers, nor creating a table with relations for each of them?
I ask for your wisdom as I don't have one or more big projects behind me and I didn't get a chance to create a DB like this until now.

Delete rows from 2 tables using a single query

I have the following database-schema:
I have the following example data:
CREATE TABLE computermapping (
ComputerMappingID int NOT NULL,
PrinterGUID char(36) NOT NULL,
ComputerGUID char(36) NOT NULL
);
INSERT INTO computermapping (ComputerMappingID, PrinterGUID, ComputerGUID) VALUES
(1, 'PRT01', 'Computer1'),
(2, 'PRT02', 'Computer1'),
(3, 'PRT01', 'Computer2'),
(4, 'PRT02', 'Computer2'),
(5, 'PRT03', 'Computer2'),
(6, 'PRT01', 'Computer3');
CREATE TABLE computerdefaultprinter (
ComputerGUID char(36) NOT NULL,
PrinterGUID char(36) NOT NULL
);
INSERT INTO computerdefaultprinter (ComputerGUID, PrinterGUID) VALUES
('Computer2', 'PRT01'),
('Computer1', 'PRT02');
Remark: Originally the tables are full of GUIDs, but I replaced them by names just for better readability.
I have also created an SQL-Fiddle with some example-data: Link
.
Taking the example data, I want to remove the printer "PRT01" from computer "Computer2".
I need to delete the appropriate row in the table computermapping and I need to delete the appropriate row in the table computerdefaultprinter. I want to delete the mentioned data in BOTH tables using ONE SINGLE statement.
According to my program-code I need to target the data by using NOT IN().
Till now I successfully used 2 statements joined/glued together by ";":
DELETE FROM computermapping WHERE PrinterGUID = 'PRT01' AND ComputerGUID NOT IN ('Computer1','Computer3');
DELETE FROM computerdefaultprinter WHERE PrinterGUID = 'PRT01' AND ComputerGUID NOT IN ('Computer1','Computer3')
This was working fine using MySQL, but it is not working with Microsoft SQL-Server. Yes, it does using the SQL Server Management Studio, but not programmatically. (count field incorrect or syntax error)
I am looking for a different approach for this task.
I did a research and it was mentioned, that it should be possible to delete the rows in both tables using "INNER JOIN", but I wasn't able to get it working and I am looking for help.
Thank you
You can add a foreign key with ON DELETE CASCADE.
For example:
CREATE TABLE computermapping (
ComputerMappingID int NOT NULL,
PrinterGUID char(36) NOT NULL,
ComputerGUID char(36) NOT NULL,
primary key (ComputerGUID, PrinterGUID)
);
INSERT INTO computermapping (ComputerMappingID, PrinterGUID, ComputerGUID) VALUES
(1, 'PRT01', 'Computer1'),
(2, 'PRT02', 'Computer1'),
(3, 'PRT01', 'Computer2'),
(4, 'PRT02', 'Computer2'),
(5, 'PRT03', 'Computer2'),
(6, 'PRT01', 'Computer3');
CREATE TABLE computerdefaultprinter (
ComputerGUID char(36) NOT NULL,
PrinterGUID char(36) NOT NULL,
foreign key (ComputerGUID, PrinterGUID)
references computermapping (ComputerGUID, PrinterGUID)
on delete cascade
);
INSERT INTO computerdefaultprinter (ComputerGUID, PrinterGUID) VALUES
('Computer2', 'PRT01'),
('Computer1', 'PRT02');
delete from computermapping
where PrinterGUID = 'PRT01' and ComputerGUID = 'Computer2';
The DELETE deletes a row in computermapping and all related rows from computerdefaultprinter as well.
See running example at SQL Fiddle.

SQL data truncation for date value

I'm having a hard time creating a simple table:
CREATE TABLE `csat` (
`csat_id` INT NOT NULL AUTO_INCREMENT,
`value` INT,
`month` DATE NOT NULL,
PRIMARY KEY (`csat_id`)
);
CREATE TABLE `migrated` (
`migrated_id` INT NOT NULL AUTO_INCREMENT,
`title` INT,
`description` INT,
`month` DATE NOT NULL,
PRIMARY KEY (`migrated_id`)
);
INSERT INTO csat
VALUES (1, 1, 2017-06-15);
INSERT INTO migrated
VALUES (1, 2, 2018-06-15);
I get the error:
Data truncation: Incorrect date value: '1996' for column 'month' at row 1
It seems like my date is in the right format:
https://www.w3schools.com/sql/func_mysql_date.asp
I'm also wondering why I need to specify a value on the csat_id, because I thought SQL would just put that in for me since its the primary key.
You have to wrap your date values in single quotation marks: '2017-06-15', not 2017-06-15. Right now, MySQL is evaluating this as 2017 minus 6 minus 15, which comes to 1996.
Also, when inserting, it's best to specify the columns you're inserting into. And if your column is set to AUTO_INCREMENT, you don't need to specify it:
INSERT INTO csat
(`value`, `month`)
VALUES
(1, '2017-06-15');
I would also consider changing your column names. Perhaps make "value" more descriptive (value of what?) And month is misleading, since it's actually a date-type column.
You haven't said which database server you're using, but generally speaking dates are inputted as strings.
You should try the following inserts;
INSERT INTO csat (`csat_id`, `value`, `month`)
VALUES (1, 1, '2017-06-15');
INSERT INTO migrated (`migrated_id`, `title`, `description`, `month`)
VALUES (1, 2, 2, '2018-06-15');
Also, you should specify which columns you're inserting into. This prevents data from being entered into the wrong fields, especially when schema changes occur.
SQL does auto increment primary key fields (if defined that way). However, you had to define it in your insert statements because you didn't specify the columns you were inserting to.
Try this instead;
INSERT INTO csat (`value`, `month`)
VALUES (1, '2017-06-15');
INSERT INTO migrated (`title`, `description`, `month`)
VALUES (2, 2, '2018-06-15');
I guess you missed the single qoutes (as per Sql standards) at first in your date and then while inserting even if the column is autoincrement you need to specify columns other than the autoincrement column so as to make sure the data you are inserting belongs to that specific column or not
Try this
INSERT INTO
csat(value,month) values
(1,'2017-06-15')

Autoincrement through IDENTITY in SQL Server 2012 Management Studio

I'm trying to do autoincrement in SQL Server 2012 Management Studio by using identity, but I'm not able to fill in values for incremental column ID. What to fill in insert values?
Part of my code looks like this:
CREATE TABLE G_Members
(
ID int(4) IDENTITY(0001, 1) PRIMARY KEY,
Jméno varchar(20) NOT NULL,
Nick varchar(20) NULL,
Příjmení varchar(20) NOT NULL,
Pohlaví char(1) NOT NULL,
Datum_Narození date NULL
);
INSERT INTO G_Members VALUES
( 'Martin', 'Mates', 'Škorník', 'M', 01-AUG-1978);
INSERT INTO G_Members VALUES
(NEXT VALUE FOR G_Members.ID, 'Ondřej', ' ', 'Panenka', 'M', 29-MAR-1983, );
If you have an Auto Increment Column you cannot insert any data for that column. You have to modify your SQL-Statement in such a way that you specify all other columns and obmit the IDENTITY column. This is achieved as follows:
INSERT INTO G_Members (Jméno,Nick,Příjmení, Pohlaví,Datum_Narození) VALUES ( 'Martin', 'Mates', 'Škorník', 'M', 01-AUG-1978);
SQL Server will insert a new value for the Id column.
Edit:
I suggest you to use nvarchar over varchar because then you will be able to store unicode values. Especially for your language this would be a better choice

Cannot insert the value NULL into column 'id', even though Column has IDENTITY property

CREATE TABLE Type1
(
TypeID TINYINT NOT NULL IDENTITY(1,1),
TypeName VARCHAR(20) NOT NULL,
Speed VARCHAR(10) NOT NULL
CONSTRAINT TypeID_pk PRIMARY KEY (TypeID)
);
CREATE TABLE Splan
(
PlanID TINYINT NOT NULL IDENTITY(1,1),
TypeID TINYINT NOT NULL,
PlanName VARCHAR(20) NOT NULL,
Quota SMALLINT NOT NULL
CONSTRAINT PlanID_pk PRIMARY KEY (PlanID)
CONSTRAINT TypeID_fk FOREIGN KEY (TypeID) REFERENCES Type1(TypeID)
);
INSERT INTO Type1(TypeName, Speed)
VALUES ('Sample type', '10Mbps'),
('Other type', '50Mbps');
^Up until there its fine
and then when I enter the following it returns "Msg 515, Level 16, State 2, Line 8
Cannot insert the value NULL into column 'TypeID' ..... column does not allows. INSERT fails." Statement terminates
INSERT INTO Splan(PlanName, Quota)
VALUES ('Some sample name', '500GB'),
('sample2, '250GB');
I've tried creating the constraints at both column and table level but the second INSERT statement still refused to enter. Double checked via the GUI and 'TypeID' definitely has an IDENTITY property.
I've looked about everywhere and this errors seems to stem from the lack of an IDENTITY property, yet its present in my creation statements and the error still comes up. Tried removing the seed and increment from IDENTITY, still nothing. Also tried inserting the data one row at a time, nothing there either.
P.S If you haven't noticed the actual names have been substituted and other columns rows have been omitted.
Since you created typID as NOT NULL, Sql is complaining that the default value (NULL) is not acceptable.
Try
INSERT INTO Splan(TypeID, PlanName, Quota)
VALUES (1, 'Some sample name', '500GB'),
(2, 'sample2, '250GB');
Where corresponding records with TypeID = 1 and TypeID = 2 are in your Type1 table.
You are creating 2 tables: Type1 which has a primary key TypeId that is auto generated
and SPlan which has a primary key PlanId that is also auto generated and a foreign key TypeId that must be supplied and cannot be null.
As written you must enter 1 or more records into Type1 first, obtain their TypeIds, then enter those TypeIds into new records in SPlan.
Incidentally, using TINYINT for your primary key data types is perfectly legal but probably a really bad idea if this is anything other than homework.
You need to supply a value for TypeID in your second query because you have a foreign key relationship with the Type1 table and because the TypeID column in the Splan table is also declared NOT NULL.
INSERT INTO Splan(TypeID, PlanName, Quota)
VALUES (1, 'Some sample name', '500GB'),
(2, 'sample2, '250GB');
Try inserting both records in a transaction using SCOPE_IDENTITY
begin tran
INSERT INTO Type1(TypeName, Speed)
VALUES ('Sample type', '10Mbps')
DECLARE #id INT = SCOPE_IDENTITY();
INSERT INTO Splan(TypeID, PlanName, Quota)
VALUES (#id, 'Some sample name', '500GB')
commit