Cast uniqueidentifier to string and use in Where clause - c#
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)
Related
C# SQL parameter limitations?
I have the following SQL command in my .Net application: sqlCommand.Text = "DECLARE #method NVARCHAR(MAX); SET #method = ' WITH selectRows AS (SELECT *, row=ROW_NUMBER() OVER(ORDER BY(SELECT 1)) FROM [' + #param + ']) SELECT ' + #param_2 + ' FROM selectRows WHERE row BETWEEN 0 AND 30;' EXEC(#method);"; sqlCommand.Parameters.AddWithValue("#param", tableName); sqlCommand.Parameters.AddWithValue("#param_2", columnString); Whenever '#param_2' is long the query won't execute. Lets say the column string looks like this: [class],[partnr],[accessoriesidentifier],[canbelinedup],[certificate],[certificate_ce],[certificate_ul],[certificate_vde],[codeletter],[construction],[craftcooling],[craftelectro],[craftfluid],[crafthydraulic],[craftlubrication],[craftmechanic],[craftpneumatic],[craftprocess],[create],[depth],[depthspacingfront],[depthspacingrear],[description1],[description2],[description3],[discount],[ecabinetmacro],[erpnr],[externaldocument1],[externaldocument2],[externaldocument3],[externalplacement],[functiongroup],[graphicmacro],[groupnumber],[groupsymbolmacro],[height],[heightspacingabove],[heightspacingbelow],[identcode],[identtype],[isaccessory],[lastchange],[lifetime],[macro3d],[maintenance],[manufacturer],[mountinglocation],[mountingspace],[note],[ordernr],[packagingprice1],[packagingprice2],[packagingquantity],[picturefile],[piecetype],[priceunit],[productgroup],[productsubgroup],[producttopgroup],[purchaseprice1],[purchaseprice2],[quantityunit],[reportid],[salesprice1],[salesprice2],[snapheight],[snapheightmiddleoffset],[spare],[stress],[supplier],[terminal],[typenr],[uniqueid],[usage],[wear],[weight],[width],[widthspacingleft],[widthspacingright],[barcount],[bardistance],[bargeometry],[barmountingplatedistance],[bottompaneldepth],[bottompaneldistance],[bottompanelprojectionback],[bottompanelprojectionfront],[bottompanelprojectionleft],[bottompanelprojectionright],[busbarholderpartnr],[busbarholdervariant],[busbarrailpartnr],[busbarrailvariant],[deliverylength],[dooroffsetright],[dooroffsettop],[doorthickness],[doortrabbet],[doortype],[hingeposition],[insertpointoffsetx],[profiledepth],[profiledistance],[profileheight],[rearpaneldistance],[rearpaneldpepth],[rearpanelprojectionbottom],[rearpanelprojectionleft],[rearpanelprojectionright],[rearpanelprojectiontop],[sidepaneldepth],[sidepaneldistance],[sidepanelprojectionback],[sidepanelprojectionbottom],[sidepanelprojectionfront],[sidepanelprojectiontop],[toppaneldistance],[toppaneldpepth],[toppanelprojectionback],[toppanelprojectionfront],[toppanelprojectionleft],[toppanelprojectionright],[vprofiledepth],[vprofilewidth],[wallthickness],[widthbottom],[widthtop],[variant],[adjustrange],[adressrange],[advancecontacts],[airgap],[assemblyspreaded],[awgfrom],[awgtill],[bendingradius],[cabledesignation],[cabledisplayform],[cablelength],[cabletype],[cableweight],[coding],[color],[connection],[connectioncrosssection],[connectiondesignation],[connectionmethod],[contactarrangement],[contacttype],[coppernumber],[creepagedistance],[crosssectionfrom],[crosssectiontill],[currentcsa],[currentiec],[currentul],[degofprotection],[design],[doordepth],[doorheight],[doormountingspace],[doorwidth],[electricalcurrent],[electricalpower],[firmwareversion],[flow],[holdingpower],[innerdiameter],[intrinsicsafety],[material],[norm],[outerdiameter],[paneldepth],[panelheight],[panelmountingspace],[panelwidth],[pincount],[pipeclass],[plcdeviceid],[plcisbuscoupler],[plcisbusdistributor],[plciscpu],[plcispowersupply],[plcobjectdescription],[plctype],[powerdissipation],[pressure],[pressurelevel],[shortcircuitresistant],[standardinvers],[strokelength],[symbolfile],[symbolnr],[technicalcharacteristics],[thread],[triggercurrent],[voltage],[voltagecsa],[voltageiec],[voltagetype],[voltageul],[widthrating],[wirecount],[wirecrosssection],[wirecrosssectionanddiameter],[wirecrosssectionunit],[variant_1],[characteristics],[connectiondescription],[connectiondesignation_1],[description],[functiondefcategory],[functiondefgroup],[functiondefid],[hasled],[hasplugadapter],[idx1],[idx2],[intrinsicsafety_1],[nesteddevicetag],[pos],[safetyrelevant],[symbol],[symbolmacro],[terminalfunction],[terminalnr],[partnr_1],[variant_2],[count],[parentvariant],[pos_1],[22235.0],[22236.0],[22237.0],[22238.0],[22239.0],[22240.0],[22241.0],[22196.1],[22196.2],[22158.1],[22158.2],[22159.1],[22159.2],[22195.1],[22195.2],[22228.1],[22228.2],[22228.3],[22228.4],[22228.5],[22228.6],[22228.7],[22228.8],[22228.9],[22228.10] The query won't execute on the server (SQL server 2005). When I remove 10 columns, the query executes without any issues. I used the sql profiler to look for any problems that the sql server receives from my application, but no problems found there. I'm really confused why it isn't working. What I try to achieve is to get a result set of all the columns from the database table WITHOUT the row column. Because if I change the SELECT #param_2 to SELECT *, i'll get all the columns plus and extra column showing the row number. To get rid of this row number I thought I just send all the column names to the SELECT statement of the query. However I'm now running in the above problem. I hope someone knows a solution that either solves the problem from above or how to get a result set of all the columns excluding the row number with a better query than I'm using. P.s: the size of the ('failing') column string is 3612 characters. I do not have too much experience with SQL itself. So excuse me if I'm making silly mistakes. EDIT: The column names depends on the user, so they can't be hardcoded in the query.
Neither your string literals nor your passed parameters are, themselves, of type nvarchar(max). You're therefore falling foul of this remark about string concatenation: If the result of the concatenation of strings exceeds the limit of 8,000 bytes, the result is truncated. However, if at least one of the strings concatenated is a large value type, truncation does not occur. What I'd probably do is change the parameter to explicitly be an nvarchar(max): sqlCommand.Parameters.Add("#param_2", SqlDbType.NVarChar,-1).Value = columnString; Alternatively you could fix it with: SET #method = CONVERT(nvarchar(max), ' WITH selectRows AS (SELECT *, row=ROW_NUMBER() OVER(ORDER BY(SELECT 1)) FROM [') + ...
Maybe this doesn't answer the question directly but it might be helpful anyway. Why do you need to use dynamioc sql at all? Why can't you use this: string sql = #" WITH CTE AS ( SELECT *, row=Row_number() OVER (ORDER BY (SELECT 1)) FROM dbo.TableName SELECT [class],[partnr],[accessoriesidentifier],[canbelinedup],[certificate],[certificate_ce],[certificate_ul],[certificate_vde],[codeletter],[construction],[craftcooling],[craftelectro],[craftfluid],[crafthydraulic],[craftlubrication],[craftmechanic],[craftpneumatic],[craftprocess],[create],[depth],[depthspacingfront],[depthspacingrear],[description1],[description2],[description3],[discount],[ecabinetmacro],[erpnr],[externaldocument1],[externaldocument2],[externaldocument3],[externalplacement],[functiongroup],[graphicmacro],[groupnumber],[groupsymbolmacro],[height],[heightspacingabove],[heightspacingbelow],[identcode],[identtype],[isaccessory],[lastchange],[lifetime],[macro3d],[maintenance],[manufacturer],[mountinglocation],[mountingspace],[note],[ordernr],[packagingprice1],[packagingprice2],[packagingquantity],[picturefile],[piecetype],[priceunit],[productgroup],[productsubgroup],[producttopgroup],[purchaseprice1],[purchaseprice2],[quantityunit],[reportid],[salesprice1],[salesprice2],[snapheight],[snapheightmiddleoffset],[spare],[stress],[supplier],[terminal],[typenr],[uniqueid],[usage],[wear],[weight],[width],[widthspacingleft],[widthspacingright],[barcount],[bardistance],[bargeometry],[barmountingplatedistance],[bottompaneldepth],[bottompaneldistance],[bottompanelprojectionback],[bottompanelprojectionfront],[bottompanelprojectionleft],[bottompanelprojectionright],[busbarholderpartnr],[busbarholdervariant],[busbarrailpartnr],[busbarrailvariant],[deliverylength],[dooroffsetright],[dooroffsettop],[doorthickness],[doortrabbet],[doortype],[hingeposition],[insertpointoffsetx],[profiledepth],[profiledistance],[profileheight],[rearpaneldistance],[rearpaneldpepth],[rearpanelprojectionbottom],[rearpanelprojectionleft],[rearpanelprojectionright],[rearpanelprojectiontop],[sidepaneldepth],[sidepaneldistance],[sidepanelprojectionback],[sidepanelprojectionbottom],[sidepanelprojectionfront],[sidepanelprojectiontop],[toppaneldistance],[toppaneldpepth],[toppanelprojectionback],[toppanelprojectionfront],[toppanelprojectionleft],[toppanelprojectionright],[vprofiledepth],[vprofilewidth],[wallthickness],[widthbottom],[widthtop],[variant],[adjustrange],[adressrange],[advancecontacts],[airgap],[assemblyspreaded],[awgfrom],[awgtill],[bendingradius],[cabledesignation],[cabledisplayform],[cablelength],[cabletype],[cableweight],[coding],[color],[connection],[connectioncrosssection],[connectiondesignation],[connectionmethod],[contactarrangement],[contacttype],[coppernumber],[creepagedistance],[crosssectionfrom],[crosssectiontill],[currentcsa],[currentiec],[currentul],[degofprotection],[design],[doordepth],[doorheight],[doormountingspace],[doorwidth],[electricalcurrent],[electricalpower],[firmwareversion],[flow],[holdingpower],[innerdiameter],[intrinsicsafety],[material],[norm],[outerdiameter],[paneldepth],[panelheight],[panelmountingspace],[panelwidth],[pincount],[pipeclass],[plcdeviceid],[plcisbuscoupler],[plcisbusdistributor],[plciscpu],[plcispowersupply],[plcobjectdescription],[plctype],[powerdissipation],[pressure],[pressurelevel],[shortcircuitresistant],[standardinvers],[strokelength],[symbolfile],[symbolnr],[technicalcharacteristics],[thread],[triggercurrent],[voltage],[voltagecsa],[voltageiec],[voltagetype],[voltageul],[widthrating],[wirecount],[wirecrosssection],[wirecrosssectionanddiameter],[wirecrosssectionunit],[variant_1],[characteristics],[connectiondescription],[connectiondesignation_1],[description],[functiondefcategory],[functiondefgroup],[functiondefid],[hasled],[hasplugadapter],[idx1],[idx2],[intrinsicsafety_1],[nesteddevicetag],[pos],[safetyrelevant],[symbol],[symbolmacro],[terminalfunction],[terminalnr],[partnr_1],[variant_2],[count],[parentvariant],[pos_1],[22235.0],[22236.0],[22237.0],[22238.0],[22239.0],[22240.0],[22241.0],[22196.1],[22196.2],[22158.1],[22158.2],[22159.1],[22159.2],[22195.1],[22195.2],[22228.1],[22228.2],[22228.3],[22228.4],[22228.5],[22228.6],[22228.7],[22228.8],[22228.9],[22228.10] FROM CTE WHERE row BETWEEN #StartRow AND #EndRow;"; using(var sqlCommand = new SqlCommand(sql, con)) { sqlCommand.Parameters.Add("#StartRow", SqlDbType.int).Value = 1; sqlCommand.Parameters.Add("#EndRow", SqlDbType.int).Value = 30; // ... } Since the column-names are specified by the user you cannot add them as parameter without dynamic sql. But you know all valid column-names, so you could check if all are valid. If you don't know all columns of a the table, have a look here and use reader.GetSchemaTable to load all columns on application start. Then you can simply add it to the sql: string sql = #" WITH CTE AS ( SELECT *, row=Row_number() OVER (ORDER BY (SELECT 1)) FROM dbo.TableName SELECT {0} FROM CTE WHERE row BETWEEN #StartRow AND #EndRow;"; sql = string.Format(sql, string.Join(",", columnList));
can dapper replace the table name?
I had expected that dapper-dot-net could replace the table name in a query like this: connection.Query("SELECT * FROM #Table WHERE [Id] = #Id", new {Table = tb, Id = id}); However, it seems to not replace the table name. Is that an expected limitation?
With the single exception of "in" (where dapper offers some voodoo), dapper is a direct ADO.NET tool - it doesn't change the query. So the real question is: can you parameterize a table name in SQL? In every database I know of: no you cannot - so that is not valid. Dapper doesn't attempt to solve that issue. Perhaps consider string.Format, remembering: to white-list the legal table-names to prevent SQL injection to use the full [square brackets] notation around the table name to allow the full range of possible names
Where are the select query values stored temporarily and how to get each value separately
I have a stored procedure with a SELECT statement that outputs one row. It is something like this: CREATE PROCEDURE [dbo].[CreateCustomer] ... INSERT INTO Customers values(, , , ,) SELECT CustomerID, FirstName, LastNam..... INSERT Roles values(, , , ..... This selects the newly stored values back from the Customers table. The second insert uses the new CustomerID to insert a new row to the Roles table. Is there a way to just get the customerID from the above select statement without querying again for the CustomerID? I have tried to declare a variable and do it like this: SELECT takenCustomerID = CustomerID, FirstName, LastNam....(rest of query statement) But I have to declare all the variables and do it this way: SELECT takenCustomerID, takenFirstName, takenLastNa... = CustomerID, FirstName, LastNam... (rest of query statement) But, I think this is bad because it wastes lot of memory on the server side. So, is there an easy way of getting individual values right away without declaring all the variables in the select statement, such as an inbuilt TEMP-like variable where I can call TEMP("customerID") and get that value? Also, Can there be more than one SELECT statement in a stored procedure? How can we get the select values from the select statement we want? I am asking more out of curiosity because I already know a way to get the value. I just want to know if there is a more elegant way.
Accessing Inserted Values It is simple. Use the OUTPUT clause to return the values you just created. DECLARE #Customers TABLE ( CustomerID uniqueidentifier, FirstName varchar(100), LastName varchar(100) ); INSERT dbo.Customers OUTPUT Inserted.* INTO #Customers SELECT newsequentialid(), #FirstName, #LastName, ...; -- now you have all the values of the new row in the `#Customers` table variable. Then you can do this: INSERT dbo.Roles SELECT CustomerID, #OtherValue, #AnotherValue, AnyotherColumnFrom#Customers FROM #Customers; If you have no further use for the values from the inserted Customer row, you could even do away with the table variable and just OUTPUT directly into the Roles table, assuming that all the values that go into that come from variables. The OUTPUT clause gives access to the inserted values using the special meta-table Inserted. However, you can use variables and expressions with constants as well. The good thing about using this method is that you can handle many inserted rows at once. If you are inserting only one row, you need only the CustomerID afterward, and you need to use it more than once, then instead do it this way: DECLARE #CustomerID uniqueidentifier = newsequentialid(); INSERT #Customer VALUES (#CustomerID, ...); INSERT #Roles VALUES (..., #CustomerID ...); By creating the GUID in advance, you don't need to get it back out of the table. By the way, newsequentialid() is probably superior to newid() if it is the clustered index (which is probably true), because you will avoid the page splits that newid would cause. Returning Multiple Result Sets This is always possible. Whatever means you are using to query will have a method that advances your data access object to the next recordset. If you're using a DataReader then look into the NextResult method. In Classic ADO, recordsets have a NextRecordset method.
Unless you redirect it manually to a table, the SELECT will go only to the output stream, so no: you can't automatically access values from a previous select. You might just be looking for SCOPE_IDENTITY(): declare #id int insert .... values (...) set #id = SCOPE_IDENTITY() In the general case of DML, another candidate is the OUTPUT clause. For more general composite selects based on existing selects, a table-variable may help: declare #foo table (id int not null, name nvarchar(100) not null) // etc insert #foo (id, name) select id, name from Foo where ... select * from #foo // for output // but we still have the #foo data available for subsequent query ... // more TSQL here With multiple select statements, it depends entirely on what API you are using; however, the raw ADO.NET API here is IDataReader, which has the NextResult() method. Typical usage for multi-grid would be: using(var reader = cmd.ExecuteReader()) { do { while(reader.Read()) { // i.e. for each row in this grid ... } } while (reader.NextResult()); // <== for each grid } Note the difference between while(...) {...} and do {...} while(...) here is because you automatically start in the first grid, but you need to progress to the first row in that grid manually.
how to design search for multiple fields in asp.net
[Form]: ![Form to be Considered][Form] [Form]: I have these form from Access. Here, I am developing search application on asp.net. I have 2 heavy databases with same data structure in which one database include approx 12000 fields and another has approx. 9000 records. I want to do search records with any criteria say, Dealer Number = 3123 and DLicenceNo = 3242314 Here, I am assuming that if user provides a field text, that only considered to be search, and others to be ignored. Is there anyway to build query for this rather using long if clauses?
Probably needs some tweaking but, start by naming all your textbox controls your column names in your database var conditionals = new Dictionary<string, string>(); foreach(Control c in Page.Controls) { if (c is TextBox) { if (!String.IsNullOrEmpty(c.Text)) conditionals.Add(c.Id, c.Text); } } From there you could be VERY careful to build a query that only has the right where clauses based on your conditionals dictionary. Ideally you can make sure it's parameterized some how to avoid all worries of SQL Injection.
I use stored procedures, passing parameters default values, like this: select field1,field2,... from table1 where (dealer_number= #dealer_number or #dealer_number='0') and (d_licence_no=#d_licence_no or #d_licence_no='0') If you're not using some parameter for this search, just send its default value, and that criteria will be ignored.
you can use Sql Case statement ,they are easy to manage , query can be like declare #SearchItem varchar(50); declare #SearchValue int; SELECT column1, column2 FROM table WHERE #SearchValue = CASE #SearchItem WHEN 'Dealer Number' THEN '' WHEN 'DLicenceNo ' THEN '' END
use the stored procedure with all search criterias as your sp arguments and pass it null when you doesn't want to apply any condition. sp will be as Create procedure usp_search ( #dealerNumber int=null, #licenseNumber int=null ) as select * from table where dealerNumber= isnull(#dealerNumber,dealerNumber) and licenseNumber = isnull(#licenseNumber ,licenseNumber )
multiple parameters for stored procedure
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>