SQL IN Clause issue when comparing values [duplicate] - c#

This question already has answers here:
Parse comma-separated string to make IN List of strings in the Where clause
(4 answers)
Closed 2 years ago.
I have the below column in table x where SharedBagsIds contains the string (1,3,4)
I am trying to write an SQL query that contains the in clause as follow
select * from .... where id in (x.SharedBagsIds)
but this line id in (x.SharedBagsIds) is generating an error
Conversion failed when converting the varchar value '1,3,4' to data type int.
is there a way to fix this issue?

This is not how the IN clause is used and you're comparing an integer (your id) to a string ('1,3,4'). You'll need to split the column value into multiple values, then check if the id matches any of the values:
WHERE (',' + RTRIM(SharedBagsIds) + ',') LIKE '%,' + #id + ',%'
See this answer.
Or consider extracting SharedBagsIds into its own table, storing comma-delimited values in a database field is not ideal.

Your table is not in 1st normal form which states that every cell should be atomic. 'SharedBagsIds' contains more than one value which should always be avoided. Read about many to many relationships in SQL and modify the table accordingly.
Suppose I have table Teacher and another table student, then to show the relationship between them, create another table which contains teacherid and studentid as the composite primary key. Thus you can show individual mapping without having the need to put multiple ids like 1,3,4 in single cell.
Hope this helps.

Related

.NET | When I search "crepe" its not returning records that contains "crépe". IQueryable collation search [duplicate]

This question already has answers here:
Ignoring accented letters in string comparison
(6 answers)
Closed 3 years ago.
Is possible to add collation search with IQueryable.
this is my code:
public IQueryable<Book> FilterQueryable(IQueryable<Book> queryabable)
{
if (!string.IsNullOrEmpty(Term))
queryabable = queryabable.Where(c => (c.Name.ToLower().Contains(Keyword.ToLower())));
}
My problem is, when I search for eg. "crepe" its not returning records that contains "crépe"
é its ignored.
EDIT 1
Text in db is stored Easy crépe recipe, this is why I used contains (LIKE).
Thank you.
As mentioned in the comments, this is something that should be done in the DB... Entity Framework simply generates a SQL script, it is the DB engine which does the actual search.
You can use the following script to change your Name column:
ALTER TABLE [dbo].[Book]
ALTER COLUMN Name NVARCHAR (256)
COLLATE SQL_LATIN1_GENERAL_CP1_CI_AI NOT NULL

Inserting PRIMARY Key value into SQL without duplicating the CHAR via ASP.NET

Once again needed help from you experts,
Heres the design
SQL
MemberID CHAR(8)
The memberID usually is "M1" "M2" and so on
However when I add into SQL via ASP.NET
The command would be something like
List memList = member.GetAllMem(); // Basically retrieve from SQL and store inside a list
AddMember("M" + Convert.ToString(memberList.count() +1);
The problem with above code is when I delete member value inside SQL the numbering of the member would have problem and can be duplicate when I insert new member (because I use the Count)
How to fix this issue?
Thanks.
I don't recommend to maintain the auto-increment by yourself but if you insist you could create a sequence and select a new value from it every time you need to insert into the table.
Create sequence like:
CREATE SEQUENCE dbo.Counter1
START WITH 1
INCREMENT BY 1 ;
GO
And every time you need a new value select the next value from it as:
SELECT NEXT VALUE FOR dbo.Counter1;
For more information please refer to https://learn.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql

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.

Add Unique Key For Nullable Columns - SQL Server

I'm using sql server 2008 R2 and would like to apply unique key constraint to nullable columns. This code works good, but if I have multiple columns to add this rule to, it would generate as many 'nullbuster' columns.
ALTER TABLE tblBranch
ADD nullbuster AS (CASE WHEN column1 IS NULL THEN BranchID ELSE NULL END);
CREATE UNIQUE INDEX UK_Column1 ON tblBranch(column1,nullbuster);
Is there any way that I could achieve the goal without generating new columns.
EDIT:
Followed #marc_s suggestion, here to create an unique key constraint.
The target column is BranchCode. Now, there is one record in the table that has NULL for BranchCode. When I try to insert a new record, with Null BranchCode, from c#, it gives an error saying - Cannot insert duplicate key for unique index UK_BranchCode.
But, when I manually insert a record in the database, it does accept null values.
Where am I going wrong.
CS
Guid gId = Guid.NewGuid();
cmd = new sqlcommand("insert into tblBranch(BranchId,BranchCode)
values(#BranchId,#BranchCode)",con);
cmd.Parameters.AddWithValue("#BranchId",gId);
cmd.Parameters.AddWithValue("#BranchCode",txtBranchCode.Text);//empty text here
con.Open();
cmd.ExecuteNonQuery();
cmd.Close();
So you're creating a nullbuster column for each nullable column you want to index? Seems like overkill....
Wouldn't it be much easier to just create filtered indexes for those nullable columns, something like:
CREATE UNIQUE INDEX UK_Column1 ON tblBranch(column1) WHERE column1 IS NOT NULL;
and thus allow any number of NULL entries, while uniquely indexing the other values. That way, you don't need to add all those nullbuster columns just to make indexing possible...
Read more about filtered indexes:
Create Filtered Indexes (on Technet)
Introduction to Filtered Index – Improve performance with Filtered Index
Update: in order to set a parameter to NULL (and not an empty string), use this code:
if(string.IsNullOrEmpty(txtBranchCode.Text))
{
cmd.Parameters.AddWithValue("#BranchCode", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#BranchCode", txtBranchCode.Text);
}
Use the filtered index suggestion provided by marc_s. You say that you are still getting a unique index violation. What does that tell you? It tells you you are inserting a duplicate key with regards to the index definition. You think, you aren't, but you definitely are.
How to debug that? You look at what you are inserting. You look at gId and txtBranchCode.Text in the debugger. Also, you look at the error message, because it says:
The duplicate key value is ...
All of these clues lead you to find that txtBranchCode.Text is not null, but an empty string. Insert NULL instead.
I suggest you move column1 to a new table and make it unique and non-nullable. Reference the Branch table using a foreign key in the new table. Populate the new table only where you have a (non-null) value for column1.
Creating a new table is the surest way to support any dependencies on column1. A column that permits nulls is not a key column but column1 apparently should be. Putting that column into a new table also happens to be the only way to satisfy Normal Form and that ought to be the default approach unless you have a very compelling reason to "denormalise" column1 into the Branch table where it doesn't seem to belong.

Grab record ID after inserting the record [duplicate]

This question already has answers here:
How to insert a record and return the newly created ID using a single SqlCommand?
(9 answers)
Return value from SQL Server Insert command using c#
(3 answers)
Closed 9 years ago.
I need to grab the ID of the record so that I can forward the user to another page with the information they just submitted. I looked at other questions regarding this and people suggest using SELECT SCOPE_IDENTITY() or OUTPUT but I'm really new to c# and SQL so I don't know exactly how to use it with my existing code. Any assistance would be greatly appreciated.
You can see I need to put the ID of the record I just inserted in the response.redirect.
pcn.Open();
pcm.Connection = pcn;
string logon_user = Request.ServerVariables["LOGON_USER"].Substring(7);
var sql = String.Format(#"INSERT INTO Transfer (Status, Type, Name) values ('{0}','{1}','{2}')", '0', TypeTxtBox.Text.Replace("'", "''"), logon_user);
pcm.CommandText = sql;
pcm.ExecuteNonQuery();
pcn.Close();
Response.Redirect("View.aspx?ID=" + id);
Yeah, I see that there are other questions similar to this but I'm looking for exact help with my code above, don't mark this duplicate because its NOT!
Firstly read up on parameterised SQL, don't ever use string concatenation for SQL as you are far more likely to fall foul of SQL injection!
To get the ID, you will need to update your code to look like this:
pcm.CommandText = "INSERT INTO Transfer (Status, Type, Name) values (#status, #type, #name);SELECT SCOPE_IDENTITY();";
object identifier = pcm.ExecuteScalar();
if your identifiers are integers, you can cast identifier to an int to get the value (adjust accordingly for Guids etc)
int id = (int)identifier;
SCOPE_IDENTITY gets last identity value inserted into an identity column in the scope.
SqlCommand.ExecuteScalar executes the script and retrieves the ID.
var sql = String.Format(#"INSERT INTO Transfer (Status, Type, Name) values ('{0}','{1}','{2}')
SELECT CAST(scope_identity() AS int)"
, '0', TypeTxtBox.Text.Replace("'", "''"), logon_user);
int ID = (int)pcm.ExecuteScalar();
You will need to use ExecuteScalar instead of ExecuteNonQuery. There are various ways to get the ID, but SCOPE_IDENTITY() is what I would use.
You can see an example on MSDN here:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx

Categories