I need to select 45 fields from a record which has 96 of them (dont ask me, but i can't normalize them, i would if i could). So, I have this page who would need all those 45 on them once it's loaded in front of the user.
Basically, I was thinking, I would make a new stored proc that would retrieve all the fieldnames and put them into one field and all the values and put them into another field and basically would end up with two parameters. I would then end up processing them in C#.
Now my question is, 1, is it the right way to do it? 2nd, if it is I can't figure out how to select the fields and put it on one parameter.
select #sql = ' select 'field1' + 'field2' + 'field3'.....
im confused on where to start?
Well for one thing you are making this way more complex than it needs to be. How in the world you have 96 columns on one table I will never know, but to select the 45 you need you're just going to have to type out 45 columns in the select statement.
Here is a sample of what the SQL would look like. Naturally I'm not going to type 45 columns, but you get the idea:
SELECT FirstName, LastName, Age, [keep going to 45] FROM tblUsers
The other issue I would like to address is the way you are executing your SQL statement. NEVER EVER EVER EVER EVER EVER EVER concatenate string variables into one SQL string. Make sure you are using parameterized queries at the very least. But I would recommend looking into Entity Framework or LINQ to SQL sometime as well.
SqlCommand scomm = new SqlCommand("UPDATE tblUsers SET FirstName='" + firstName + "' WHERE UserID='" + userId + "'");
That ^^^ equals very bad. Think about what would happen if a user decided to be sneaky and make his first name Harry' AND Admin='true. You might think, "Oh, well I'll just do firstName = firstName.Replace("'","''"); on all my variables. If you do that I will personally come punch you. Parameterize your queries like this:
SqlCommand scomm = new SqlCommand("UPDATE tblUsers SET FirstName=#FirstName WHERE UserID=#UserID");
scomm.Parameters.Add(new SqlParameter("FirstName", firstName));
scomm.Parameters.Add(new SqlParameter("UserID", userId));
That ^^^ equals much better.
EDIT Also if you ever get a chance to re-work that monster of a table you have, try refactoring subsets of fields into their own entity (table) and linking them via a reference ID. For example, say I have a table called [tlbUsers] and it contains info about a specific user. Like this:
[tlbUsers]
UserID
FirstName
LastName
Age
Username
StreetAddress
City
State
ZipCode
Country
Phone
Consider refactoring that so that related values have their own table. You could take all the address info from this users table and put it in a table called tlbAddresses. Not only would that make it easier to deal with when pulling in the data, but it could potentially save you space in the database. For instance, if Harry and Sally both live in the same home, they could reference the same address record.
[tlbUsers]
FirstName
LastName
Age
Username
AddressID
Phone
[tlbAddresses]
AddressID
Street
City
State
ZipCode
Country
I am having a little trouble understanding your question, however if you want to pass a variable number of parameters to a stored procedure there are two ways I can think of that you can do it, which require SQL Server 2005 and SQL Server 2008 respectively.
The first leverages XML. Have your procedure take a varchar(max) argument and then you can easily split it out. For example, if you comma separate what you want, you could:
DECLARE #xml xml
SET #xml = cast('<x>'+replace(#yourArg,',','</x><x>')+'</x>' as xml)
SELECT N.value('.','varchar(max)') AS myArgName FROM #xml.nodes('x') AS T(N)
Also, you could leverage table valued variables and select your inputs into a table and pass that to the stored procedure. See http://www.sqlteam.com/article/sql-server-2008-table-valued-parameters for an example.
You can return the data as xml in one field.
Test table
create table TestTbl(ID int, F1 int, F2 int, F3 int, F4 int) -- to F96
Test data
insert into TestTbl values (1, 2, 3, 4, 5)
Query
select
(select
F1, F2, F3, F4 -- to F45
from TestTbl
where ID = 1
for xml path('root'), type) as XMLData
Result
XMLData
-----------------------------------------------------
<root><F1>2</F1><F2>3</F2><F3>4</F3><F4>5</F4></root>
XML in XMLData field
<root>
<F1>2</F1>
<F2>3</F2>
<F3>4</F3>
<F4>5</F4>
</root>
Related
figured out answer and edited question so it works now.
Here is my example
CustomerID column in my database is set to uniqueidentifier.
C#
string cid = ( This is a variable; it could be ANY guid the user chooses. )
Query String
" SELECT * FROM [db]
WHERE (CAST(CustomerID AS VARCHAR(100)) LIKE '%"+cid+#"%');"
The CustomerID field does not evaluate for a rows with the same cid. So the cid is having trouble being evaluated with the uniqueidentifier (CustomerID).
Don't build your query by string concatenating user input into the query. It can lead to sql injection which is a serious issue.
Instead you should use parametrized queries, where you pass the user input to the query in the form of a parameter. The underlying framework/driver/etc will then make sure that the user input is prepared in a way that cannot accidentally become sql code.
Something like this:
Guid cidAsGuid = new Guid(cid);
MySqlCommand command = new MySqlCommand("SELECT * FROM [db] WHERE CustomerId = #customerID");
command.Parameters.AddWithValue("#customerID", cidAsGuid);
And then you can use the command to execute a reader or fill an adapter or some other thing you need to do.
This has the added benefit that an index on the CustomerId column can be used to speed up the query, whereas if you search by converting the CustomerId from a Guid to a string means the database will have to scan the whole table. For small tables you won't notice much difference but for large tables the difference will be significant.
I'm seeing a few possible issues;
There's no condition defined for the ISNULL e.g. ISNULL(Column,valueifnull).
Also the actual query must specify a column to use ISNULL in that structure.
There's a missing "closing bracket" on the ISNULL.
Something such as this should work:
SELECT ISNULL(
(
SELECT Column1 FROM MyTable
WHERE (CAST(CustomerID AS VARCHAR(100)LIKE '%"+cid+#"%')
)
,'')
You don't need like if CustomerID is uniqueidentifier too.
WHERE (CAST(CustomerID AS VARCHAR(36)) = #cid)
In my project I need to insert a table data from another table. I trying to write this sql code. But this order by option is not working while inserting the data. Here is my code:
INSERT INTO StudentInfo_MeritPosition
( ID,
Name,
MeritPosition,
SSC,
HSC,
First,
Second,
Third,
Fourth,
Fifth
)
SELECT ID,
Name,
MeritPosition,
SSC,
HSC,
First,
Second,
Third,
Fourth,
Fifth
FROM StudentInfo
ORDER BY MeritPosition
The above code inserting data into database. But not in the order format.
I need to know if there any way our for this problem. Thank you.
SQL tables represent unordered sets. When you retrieve data from the table, the data has no particular order, unless you specify order by. So, you can just retrieve the data as:
select mp.*
from StudentInfo_MeritPosition mp
order by mp.MeritPosition;
You can make this query more efficient by adding an index on StudentInfo_MeritPosition(MeritPosition).
You can use a temp table to order in any way you want. In my opinion it's easier to assemble a temp table first, then order those results and select them into the table you're trying to populate in a given order. This way you can translate it to a stored procedure and feed it the parameter of "column name" and "ASC or DESC." The temp table will take a bit longer to work with since you're selecting, ordering, reselecting, and inserting. However, the end result is much more robust than a 1 time query allowing you to use any column name, and ASC or DESC. Just remember that when you do select the results into your permanent table, you leave out the primary key (typically [P_ID]) column form your select into statement.
So, to improve on Gordon's answer, you could write something like what follows:
DECLARE #fromTbl, #sortCol, #orderByCol VARCHAR(50)
EXEC('
select mp.*
from /* StudentInfo_MeritPosition* / ' + #fromTbl + 'mp
order by /* mp.MeritPosition */ mp.' + #orderByCol + ' ' + #sortOrder;'
/* If you wanted to debug it and make sure your parameters are being
generated correctly, you can use the PRINT function instead of
Exec('Your statement above') */
Then, if you turn it into a SP you can pass in the three parameters table, order by column, and sort order (ASC|DESC) and bypass the temp table creation process I mentioned previously.
Try this.
INSERT
/*+append*/
INTO StudentInfo_MeritPosition
( ID,
Name,
MeritPosition,
SSC,
HSC,
First,
Second,
Third,
Fourth,
Fifth
)
SELECT *
FROM (
SELECT ID,
Name,
MeritPosition,
SSC,
HSC,
First,
Second,
Third,
Fourth,
Fifth
FROM StudentInfo
ORDER BY MeritPosition );
Im writing a C# web page thats tied to a listview. My client would like to be able to type in something or part of something that it would show results. For example he wants a textbox where he may put in a phone number, part of a phone number, a name, city or whatever and there would be a SP of sorts that finds then lists the info. How can I accomplish this in either a SQL Sp or within VS 2010?
SELECT cols
FROM tbl
WHERE field LIKE '%' + #input + '%'
As several others have suggested, use the LIKE operator.
However, do NOT just put the data the user typed in directly into your LIKE clause like others have suggested. This leads to a very simple and very dangerous vulnerability known as a SQL injection attack.
If you insert the user's input directly into
SELECT cols FROM tbl WHERE field LIKE '%' + input + '%'
then a user could put the following in the text box:
;DROP TABLE tbl; --
(as an example), which makes your SQL statement become:
SELECT cols FROM tbl WHERE field LIKE '%'; (the first part of your query)
DROP TABLE tbl; (the injected sql that you don't want to let people run; drop the database table)
-- '%' (the rest of your previous query is commented out)
Always make sure you used parametrised SQL statements, or at the minimum sanitize your inputs. You really don't want people to be able to run arbitrary SQL on your database server.
Jeff Atwood (of SO fame) has a short posting on this.
And it is worth reading this too :)
Most everyone has hit on part of the solution -- use the LIKE operator.
But I think another aspect of the problem can be addressed in SQL.
Create a computed varchar(MAX) column. Turn on a full text index on this field. Then all you need to do is do a sql like:
SELECT * from <TABLE_NAME> WHERE Keywords like '%<search term>%'
This way you don't have to do phone like <search> or name like <search> etc.
Use the LIKE operator.
SELECT * FROM Table WHERE PhoneNumber LIKE '%value%' OR Name LIKE '%value%' OR
City LIKE '%value%'
If you want to use one textbox which could contain many different kinds of data, you need to be specific in your code about which database tables and columns you will search, and in what order.
For example, you might write a query that does this:
First, search in the Customer table
in the FirstName and LastName columns
for a name LIKE the one in the
textbox. SELECT the CustomerID for
all of the matches.
Next, search in both the Customer
table and the Supplier table, in the
PhoneNumber column, for a phone
number LIKE the one in the textbox.
SELECT the CustomerID or SupplierID
for all of the matches. If any results are found, combine them with the results of the first query.
Continue searching for street
addresses, and querying other tables.
Add new records to the resultset as
you go along.
After you have queried all of the tables that you want to search in, you will have a resultset containing ID's. You need to do another series of SELECTs to get the information you want to display to the user. If you mix customers and suppliers (and employees, etc), this could become quite complicated.
As you can see from this, it would be much easier to have separate textboxes for each search criteria. One textbox for first name, another for last name, a third for company name. A separate textbox for phone number. And if you are mixing data for customers, suppliers, employees, etc, you should have the user indicate (perhaps on a dropdown list or with checkboxes) which types of people to search, so you know which tables to query.
I have a table called Student with a lot foreign keys that will be used after to filter students(table rows).
The structure of this table is like:
StudentId GenderId DegreeId NatioanlityId
1 2 2 3
....
As a student can speak one or more language,the Sudent Table is linked to language table like this
StudentId LangaugeId
1 1
1 2
1 3
And a student can chose one or many subjects for exam:
StudentId ExamId
1 1
1 2
....
In my asp.net page I would like to filter students via checkbox using ajax
for example, student having female and male gender with Degree 1,speaking language 1,2... I filter rows in a stored proc using user defined table,and I have to use a lot of IF statements like this
if(EXISTS(SELECT GenderId FROM #GenderTable))
if(EXISTS(SELECT DegreeId FROM #DegreeTable))
if(....)
else
if(...)
How can I avoid all the IF statements? I have more than 5 filters.It's boring. Any one have any ideas?
Thanks in advance.
I am assuming that your query is returning a list of students who meet the criteria? If so one way to do this would be to build a where clause following this format
Where
(#Param1 IS NULL OR Field1 = #Param1)
AND (#Param2 IS NULL OR Field2 = #Param2)
This can get ugly and may not perform well depending on how many filters are possible vs used and how your indexing is built.
Another option would be to use dynamic SQL. You can generate it either in your .net code or in a SQL stored proc. Basically end up with something along the lines of:
Set #Query = /* base select statement */
If #Param1 IS NOT NULL
Set #Query = #Query + 'AND Field1 = #Param1'
If #Param2 IS NOT NULL
Set #Query = #Query + 'AND Field2 = #Param2'
Exec sp_executesql #Query, #ParamList, #Param1, #Param2
This can get even harder to read and debug but it will commonly perform better since you are only looking at the fields that are actually being filtered against. However if you use dynamic SQL there are some critical points that you need to be aware of, Injection Attacks being at the top of the list. http://www.sommarskog.se/dynamic_sql.html is a good resource on what should and should not be done with dynamic SQL.
I've taken over an ASP.NET application that needs to be re-written. The core functionality of this application that I need to replicate modifies a SQL Server database that is accessed via ODBC from third party software.
The third-party application creates files that represent printer labels, generated by a user. These label files directly reference an ODBC source's fields. Each row of the table represents a product that populates the label's fields. (So, within these files are direct references to the column names of the table.)
The ASP.NET application allows the user to create/update the data for these fields that are referenced by the labels, by adding or editing a particular row representing a product.
It also allows the occasional addition of new fields... where it actually creates a new column in the core table that is referenced by the labels.
My concern: I've never programmatically altered an existing table's columns before. The existing application seems to handle this functionality fine, but before I blindly do the same thing in my new application, I'd like to know what sort of pitfalls exist in doing this, if any... and if there are any obvious alternatives.
It can become problem when too many columns are added to tables, and you have to be careful if performance is a consideration (covering indexes are not applicable, so expensive bookmark lookups might be performed).
The other alternative is a Key-Value Pair structure: Key Value Pairs in Database design, but that too has it's pitfalls and you are better off creating new columns, as you are suggesting. (KVPs are good for settings)
One option I think is to use a KVP table for storing dynamic "columns" (as first mentioned by Mitch), join the products table with the KVP table based on the product id then pivot the results in order to have all the dynamic columns in the resultset.
EDIT: something along these lines:
Prepare:
create table Product(ProductID nvarchar(50))
insert Product values('Product1')
insert Product values('Product2')
insert Product values('Product3')
create table ProductKVP(ProductID nvarchar(50), [Key] nvarchar(50), [Value] nvarchar(255))
insert ProductKVP values('Product1', 'Key2', 'Value12')
insert ProductKVP values('Product2', 'Key1', 'Value21')
insert ProductKVP values('Product2', 'Key2', 'Value22')
insert ProductKVP values('Product2', 'Key3', 'Value23')
insert ProductKVP values('Product3', 'Key4', 'Value34')
Retrieve:
declare #forClause nvarchar(max),
#sql nvarchar(max)
select #forClause = isnull(#forClause + ',', '') + '[' + [Key] + ']' from (
select distinct [Key] from ProductKVP /* WHERE CLAUSE */
) t
set #forClause = 'for [Key] in (' + #forClause + ')'
set #sql = '
select * from (
select
ProductID, [Key], [Value]
from (
select k.* from
Product p
inner join ProductKVP k on (p.ProductID = k.ProductID)
/* WHERE CLAUSE */
) sq
) t pivot (
max([Value])' +
#forClause + '
) pvt'
exec(#sql)
Results:
ProductID Key1 Key2 Key3 Key4
----------- --------- --------- --------- -------
Product1 NULL Value12 NULL NULL
Product2 Value21 Value22 Value23 NULL
Product3 NULL NULL NULL Value34
It very much depends on the queries you want to run against those tables. The main disadvantage of KVP is that more complex queries can become very inefficient.
A "hybrid" approach of both might be interesting.
Store the values you want to query in dedicated columns and leave the rest in an XML blob (MS SQL has nice features to even query inside the XML) or alternatively in a KVP bag. Personally I really don't like KVPs in DBs because you cannot build application logic specific indixes anymore.
Just another approach would be not to model the specific columns at all. You create generic "custom attribute" tables like: Attribute1, Attribute2, Attribute3, Attribute4 (for the required data type etc...) You then add meta data to your database that describes what AttrX means for a specific type of printer label.
Again, it really depends on how you want to use that data in the end.
One risk is the table getting too wide. I used to maintain a horrible app that added 3 columns "automagically" when new values were added to some XML (for some reason it thought everything would be a string a date or a number- hence the creation of 3 columns).
There are other techniques like serializing a BLOB or designing the tables differently that may help.