Database id column or code column - c#

I am working on a project where I have to implement some new functionality.
In the process I have to design some tables and build some editors for that data.
I have one table for categories and one for types.
On client side I have to build some lists using those types, but each list must use types from only one category.
I don't like the idea to use PKs in my C#. I would rather create a column name "Code" in the category table and use that in my C# code, when preparing the lists.
EDIT: I do not mean removing the PK (I will have an int base Id column). I mean adding another column to the category ("Code") to use jsut in C# as string constants, instead of ids.
Is this an okay idea?

If I've understood your question, I would recommend the following structure for your tables:
Table Category
ID Int -- primary key
Code Varchar(8) -- Code value displayed to users
Description Varchar(100)
Table Item
ID Int -- primary key
CategoryID Int -- foreign key to Category
Code Varchar(8) -- Code value displayed to users
Description Varchar(100)
This way, if you change a Category record's Code, nothing changes behind the scenes, and the key values are never exposed to your users.

Related

How to Auto-increment non-integer primary key in sql-server? [duplicate]

Can I make a primary key like 'c0001, c0002' and for supplier 's0001, s0002' in one table?
The idea in database design, is to keep each data element separate. And each element has its own datatype, constraints and rules. That c0002 is not one field, but two. Same with XXXnnn or whatever. It is incorrect , and it will severely limit your ability to use the data, and use database features and facilities.
Break it up into two discrete data items:
column_1 CHAR(1)
column_2 INTEGER
Then set AUTOINCREMENT on column_2
And yes, your Primary Key can be (column_1, column_2), so you have not lost whatever meaning c0002 has for you.
Never place suppliers and customers (whatever "c" and "s" means) in the same table. If you do that, you will not have a database table, you will have a flat file. And various problems and limitations consequent to that.
That means, Normalise the data. You will end up with:
one table for Person or Organisation containing the common data (Name, Address...)
one table for Customer containing customer-specific data (CreditLimit...)
one table for Supplier containing supplier-specific data (PaymentTerms...)
no ambiguous or optional columns, therefore no Nulls
no limitations on use or SQL functions
.
And when you need to add columns, you do it only where it is required, without affecting all the other sues of the flat file. The scope of effect is limited to the scope of change.
My approach would be:
create an ID INT IDENTITY column and use that as your primary key (it's unique, narrow, static - perfect)
if you really need an ID with a letter or something, create a computed column based on that ID INT IDENTITY
Try something like this:
CREATE TABLE dbo.Demo(ID INT IDENTITY PRIMARY KEY,
IDwithChar AS 'C' + RIGHT('000000' + CAST(ID AS VARCHAR(10)), 6) PERSISTED
)
This table would contain ID values from 1, 2, 3, 4........ and the IDwithChar would be something like C000001, C000002, ....., C000042 and so forth.
With this, you have the best of both worlds:
a proper, perfectly suited primary key (and clustering key) on your table, ideally suited to be referenced from other tables
your character-based ID, properly defined, computed, always up to date.....
Yes, Actually these are two different questions,
1. Can we use varchar column as an auto increment column with unique values like roll numbers in a class
ANS: Yes, You can get it right by using below piece of code without specifying the value of ID and P_ID,
CREATE TABLE dbo.TestDemo
(ID INT IDENTITY(786,1) NOT NULL PRIMARY KEY CLUSTERED,
P_ID AS 'LFQ' + RIGHT('00000' + CAST(ID AS VARCHAR(5)), 5) PERSISTED,
Name varchar(50),
PhoneNumber varchar(50)
)
Two different increments in the same column,
ANS: No, you can't use this in one table.
I prefer artificial primary keys. Your requirements can also be implemented as unique index on a computed column:
CREATE TABLE [dbo].[AutoInc](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Range] [varchar](50) NOT NULL,
[Descriptor] AS ([range]+CONVERT([varchar],[id],(0))) PERSISTED,
CONSTRAINT [PK_AutoInc] PRIMARY KEY ([ID] ASC)
)
GO
CREATE UNIQUE INDEX [UK_AutoInc] ON [dbo].[AutoInc]
(
[Descriptor] ASC
)
GO
Assigning domain meaning to the primary key is a practice that goes way, way back to the time when Cobol programmers and dinosaurs walked the earth together. The practice survives to this day most often in legacy inventory systems. It is mainly a way of eliminating one or more columns of data and embedding the data from the eliminated column(s) in the PK value.
If you want to store customer and supplier in the same table, just do it, and use an autoincrementing integer PK and add a column called ContactType or something similar, which can contain the values 'S' and 'C' or whatever. You do not need a composite primary key.
You can always concatenate these columns (PK and ContactType) on reports, e.g. C12345, S20000, (casting the integer to string) if you want to eliminate the column in order to save space (i.e. on the printed or displayed page), and everyone in your organization understands the convention that the first character of the entity id stands for the ContactType code.
This approach will leverage autoincrementing capabilities that are built into the database engine, simplify your PK and related code in the data layer, and make your program and database more robust.
First let us state that you can't do directly. If you try
create table dbo.t1 (
id varchar(10) identity,
);
the error message tells you which data types are supported directly.
Msg 2749, Level 16, State 2, Line 1
Die 'id'-Identitätsspalte muss vom
Datentyp 'int', 'bigint', 'smallint',
'tinyint' oder 'decimal' bzw.
'numeric' mit 0 Dezimalstellen sein
und darf keine NULL-Werte zulassen.
BTW: I tried to find this information in BOL or on MSDN and failed.
Now knowing that you can't do it the direct way, it is a good choice to follow #marc_s proposal using computed columns.
Instead of doing 'c0001, c0002' for customers and 's0001, s0002' for suppliers in one table, proceed in the following way:
Create one Auto-Increment field "id" of Data Type "int (10) unsigned".
Create another field "type" of Data Type "enum ('c', 's')" (where c=Customer, s=Supplier).
As "#PerformanceDBA" pointed out, you can then make the Primary Key Index for two fields "id" & "type", so that your requirement gets fulfilled with the correct methodology.
INSERT INTO Yourtable (yourvarcharID)
values('yourvarcharPrefix'+(
SELECT CAST((SELECT CAST((
SELECT Substring((
SELECT MAX(yourvarcharID) FROM [Yourtable ]),3,6)) AS int)+1)
AS VARCHAR(20))))
Here varchar column is prefixed with 'RX' then followed by 001, So I selected substring after that prefix of it and incremented the that number alone.
We can add Default Constraint Function with table definition to achieve this.
First create table -
create table temp_so (prikey varchar(100) primary key, name varchar(100))
go
Second create new User Defined Function -
create function dbo.fn_AutoIncrementPriKey_so ()
returns varchar(100)
as
begin
declare #prikey varchar(100)
set #prikey = (select top (1) left(prikey,2) + cast(cast(stuff(prikey,1,2,'') as int)+1 as varchar(100)) from temp_so order by prikey desc)
return isnull(#prikey, 'SB3000')
end
go
Third alter table definition to add default constraint -
alter table temp_so
add constraint df_temp_prikey
default dbo.[fn_AutoIncrementPriKey_so]() for prikey
go
Fourth insert new row into table without specifying value for primary column-
insert into temp_so (name) values ('Rohit')
go 4
Check out data in table now -
select * from temp_so
OUTPUT -
prikey name
SB3000 Rohit
SB3001 Rohit
SB3002 Rohit
SB3003 Rohit
you may try below code:
SET #variable1 = SUBSTR((SELECT id FROM user WHERE id = (SELECT MAX(id) FROM user)), 5, 7)+1;
SET #variable2 = CONCAT("LHPL", #variable1);
INSERT INTO `user`(`id`, `name`) VALUES (#variable2,"Jeet");
1st line to get last inserted Id by removing four character than increase one value and set to a variable1
2nd line to make complete id with four character prefix and assign to variable2
insert new value with generated new primary key = variable2
you should have minimum one data in this table to work above SQL
No. If you really need this, you will have to generate ID manually.

How do I remove unique constraints from tables without hard coding rows?

I am not sure if this is a duplicate or not as there have been several how to's for removing unique constraint. I feel like my question is just different enough to warrant a new question. I have C# code which builds up mysql queries. They end out looking like this:
CREATE table_B like table_A;
I then alter each of the newly created tables to add history details similar to this:
ALTER TABLE table_B
MODIFY COLUMN primary_column int(11) NOT NULL,
DROP KEY `PRIMARY`,
ENGINE = MyISAM,
ADD db_action_type VARCHAR(8) DEFAULT 'insert' FIRST,
ADD revision INT(6) NOT NULL AUTO_INCREMENT AFTER db_action_type,
ADD dt_datetime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER revision,
ADD PRIMARY KEY(revision);
Essentially, I am creating history tables. The trouble I am having is that I cannot add additional rows if the table has a unique constraint. I could do some queries to get a list of unique constraint columns for each table and alter each column individually or as part of this alter table. I am just wondering if there is an easy way which does not require knowing any of the column names. Is there any sort of blanket effect drop unique attribute without caring about specifics?

How would I create "multiple choice" columns in Local Database?

I am using local database for first time with my WPF project. I have the database setup, and I am connecting fine ETC. Ther eare some columns which I want to be multiple choice, either between a few values or a whole bunch of values. Problem is obviously human error will make typos now and then when inputting the data.
How would I go about making the data entry give the user a multiple choice? So for example, I have a column called "Category", and at the moment (this will be expanded later) I only want to allow the following options:
Bronze
Misc
I have the columns set to nvarchar(50) at present, but typing the same string manually constantly... not what I would like to be doing TBH... so... Could I set it so that there are a list of predefined values it will accept? :)
thanks :D
You can use CHECK constraint of any complexity on your table column(s). Check MSDN here
So your table definition would be as:
CREATE TABLE T
(
Category nvarchar(50) CHECK (Category in ('Bronze','Misc'))
)
If you expect your list of possible values to change in the future and you do not want to change a table definition, you can create a separate table with the list of values and use the foreign key.
CREATE TABLE Categories
(
Id int PRIMARY KEY,
CategoryName nvarchar(50)
)
INSERT INTO Categories VALUES (1, 'Bronze'), (2, 'Silver'), (3, 'Misc')
CREATE TABLE T
(
CategoryId int REFERENCES Categories
)

Holding different datatypes dynamically in database

Lets say I have a table Person and I need that a user can add different attributes to him/herself.
User should be able to add a date, string, number, boolean, multiple values.
Lets say he wants to add:
Date of birth
Name
Heigth
Children names
How would I hold this in database?
I have 2 ideas:
I can hold all the values as string or varchar and always parse the value back to original format when used. Multiple values holding like text1#text2#text3 or similar.
Having a table, where there are columns for each : date, string, number and only the one that is needed will be populated and other will stay nulls.
Any suggestions?
Good database design should always be N:1 (many to one) or 1:1 (one to one), never 1:N (one to many) or N:N (many to many), meaning that if you have multiple related fields of a user, you should make a new table that refers to the user.
Since a user can only have one birth date though, you should keep that as a column to the Users table.
For example, in this case you want children names as the "multiple", assigned to one user.
A simple table for that could look like this:
ID int primary key
UserID int references User(ID)
Name varchar
That way, you can make multiple children names for one user, while still being able to keep constraints in the database (which helps ensure code correctness if you're interfacing with it through an application!)
Some people will suggest having a table for each of the values, just to avoid nulls. For example, to store their birthdate, you make a table similar to the Children names table above, since you won't have to make a column in the Users table that might be null.
Personally I think using nulls are fine, as they allow you to see if there is a relevant result set without joining (or worse, left joining) an entire table of potentially irrelevant information.
Use your second approach. In your table 'Person', have a row for each record that has multiple columns each which holds a single value for you desired fields.
So..
tbPerson
ID | Date Of Birth | Name | Height | Childrens names | etc...
To Create a table...
CREATE TABLE tbPerson([ID] INT IDENTITY(1,1), [Date Of Birth] DATE, [Name] VARCHAR(50), Height INT, [Childrens names] VARCHAR(250))
This is the best and easiest way and enables editing 1 field of a persons records simple. In your first approach you will have endless nightmares storing everything a 1 long string.

Database Design Deleting parent and his children in nested Parent-child situation

In Oracle I have a table called Category consisting of three columns:
ID = which is system produced unique key ,
Catgeory_name = which is 300 char ,
and parent_id = which either could be -1 which means no parent for this category, or it could be a value from the ID column described earlier as the parent_id.
The problem is when I delete a category who is a parent, I need to automatically delete all the children as well. My question is : Does SQL provide any means to do this automatically or should I take care of it in my upper layer langugae which is C#.
For example if there was a foreign key situation between two tables, I know SQL provides ON DELETE CASCADE to delete the dependent records as well as the parent record upon a delete request for the origianal record.
However, I don't know of any way in SQL that would take care of the above situation automatically, meaning when the parent is deleted in the above table, all the children get deleted as well.
Thanks in advance for your help.
If the parent_id was set to NULL if there was no parent, you could define a foreign key on category that referenced the primary key in category
SQL> create table category (
2 id number primary key,
3 category_name varchar2(300),
4 parent_id number references category( id )
5 );
Table created.
You could then declare that foreign key constraint to automatically delete the children when the parent row is deleted.
If you really want to use a magic value of -1 to indicate the absence of a parent rather than using a proper NULL, you could potentially insert a row into the category table with an id of -1 and then create the foreign key constraint. But that is much less elegant than using a NULL.

Categories