Mysql Query with AND condition is not working as Expected [duplicate] - c#

Let's say a have a stored procedure SetCustomerName which has an input parameter Name, and I have a table customers with column Name.
So inside my stored procedure I want to set customer's name. If I write
UPDATE customers SET Name = Name;
this is incorrect and I see 2 other ways:
UPDATE customers SET Name = `Name`;
UPDATE customers SET customers.Name = Name;
First one works, but I didn't find in documentation that I can wrap parameters inside ` characters. Or did I miss it in the documentation (link is appreciated in this case).
What other ways are there and what is the standard way for such a case? Renaming input parameter is not good for me (because I have automatic object-relational mapping if you know what I mean).
UPDATE:
So, there is a link about backticks (http://dev.mysql.com/doc/refman/5.0/en/identifiers.html) but it's not explained deep enough how to use them (how to use them with parameters and column names).
And there is a very strange thing (at least for me): You can use backticks either way:
UPDATE customers SET Name = `Name`;
//or
UPDATE customers SET `Name` = Name;
//or even
UPDATE customers SET `Name` = `Name`;
and they all work absolutely the same way.
Don't you think this is strange? Is this strange behavior explained somewhere?

Simplest way to distinguished between your parameter and column (if both name is same) is to add table name in your column name.
UPDATE customers SET customers.Name = Name;
Even you can also add database prefix like
UPDATE yourdb.customers SET yourdb.customers.Name = Name;
By adding database name you can perform action on more than 1 database from single store procedure.

I think that your first example is actually backwards. If you're trying to set the "Name" column to the "Name" input parameter, I believe it should be:
UPDATE customers SET `Name` = Name;
And for the second example, you can set table aliases the same way that you do in all other statements:
UPDATE customers AS c SET c.Name = Name;

Not necessarily correct, but a fair way to better argument/parameter management, as well readability with easier understanding, especially while working with the SQL;
DROP PROCEDURE IF EXISTS spTerminalDataDailyStatistics; DELIMITER $$
CREATE PROCEDURE spTerminalDataDailyStatistics(
IN TimeFrom DATETIME,
IN DayCount INT(10),
IN CustomerID BIGINT(20)
) COMMENT 'Daily Terminal data statistics in a date range' BEGIN
# Validate argument
SET #TimeFrom := IF(TimeFrom IS NULL, DATE_FORMAT(NOW(), '%Y-%m-01 00:00:00'), TimeFrom);
SET #DayCount := IF(DayCount IS NULL, 5, DayCount);
SET #CustomerID := CustomerID;
# Determine parameter
SET #TimeTo = DATE_ADD(DATE_ADD(#TimeFrom, INTERVAL #DayCount DAY), INTERVAL -1 SECOND);
# Do the job
SELECT DATE_FORMAT(TD.TerminalDataTime, '%Y-%m-%d') AS DataPeriod,
COUNT(0) AS DataCount,
MIN(TD.TerminalDataTime) AS Earliest,
MAX(TD.TerminalDataTime) AS Latest
FROM pnl_terminaldata AS TD
WHERE TD.TerminalDataTime BETWEEN #TimeFrom AND #TimeTo
AND (#CustomerID IS NULL OR TD.CustomerID = #CustomerID)
GROUP BY DataPeriod
ORDER BY DataPeriod ASC;
END $$
DELIMITER ;
CALL spTerminalDataDailyStatistics('2021-12-01', 2, 1801);

Using backticks in MySQL query syntax is documented here:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
So yes, your first example (using backticks) is correct.

Here is the link you are asking for:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
The backticks are called "identifier quote" in MySql

Related

Incorrect syntax near '?' while inserting HTML as NVARCHAR

We have a textarea in which the users are able to write anything, it is a dynamic view which will be loaded later. When the user is ready to save it, the textarea is sent so be saved in the database.
The problem is, sometimes it works and sometimes it doesn't. The times it doesn't work is because we received:
Incorrect syntax near '?'.
We have replaced all single quotes with two single quotes, and we have made sure that it reaches the database correctly.
ALTER STORED PROCEDURE dbo.SaveHtml #htmlValue NVARCHAR(MAX)
AS
DECLARE #SQL_QUERY NVARCHAR(MAX);
SET #SQL_QUERY = N'UPDATE TEMP_TABLE SET BLOCK_1 = N{VALUE} WHERE ID = 12';
SET #SQL_QUERY = REPLACE(#SQL_QUERY,'{VALUE}', ISNULL(#htmlValue,NULL));
EXECUTE (#SQL_QUERY);
Basically that is what it does, we create a dynamic SQL because there are parameters which are dynamic, but for this example I omitted it.
It works, but sometimes when the user copies and pastes data from Word, the string arrives with characters like иĆÊô￴∀⠢Ĉ!ࠀސȁސ﷿ ױ﹗£΀ਮշωԊӍԊӍ̳¡﹩fȒ@† ™ IJ囌垐輈׶č靀ミ, and later we received the indicated error.
Even sometimes it arrives with those characters (not necessarily those exactly or in the same order) and it is saved successfully.
For the example mentioned if I delete the first ސ character the string is saved successfully.
'<p class="MsoNormal" style="margin-top:0cm;margin-right:0cm;margin-bottom:0cm;
margin-left:36.2pt;text-align:justify;text-indent:-18.0pt;line-height:normal;иĆÊô￴∀⠢Ĉ!ࠀސȁސ﷿ ױ﹗£΀ਮշωԊӍԊӍ̳¡﹩fȒ@† ™ IJ囌垐輈׶č靀ミ...'
When I debug to see the dynamic SQL and I print it, it looks like:
UPDATE TEMP_TABLE SET BLOCK_1 = N'<div class="note-editable" contenteditable="true" role="textbox" aria-multiline="true" ...' WHERE ...
As these are the strings that we saved.
This is currently in production because it works, but the times that it does not work are exceptional. When Chinese, Arabic and more special characters arrive it becomes a lottery that our code works.
How could I solve this problem?
You are not quoting your string, nor treating it as a NVARCHAR. Instead of this:
SET #SQL_QUERY = REPLACE(#SQL_QUERY,'{VALUE}', ISNULL(#htmlValue,NULL));
You need this for syntactically correct SQL:
SET #SQL_QUERY = REPLACE(#SQL_QUERY,'{VALUE}', ISNULL('N''' + #htmlValue + '''','NULL'));
However the correct and safe way to do this is using sp_executesql with a proper parameter as follows:
SET #SQL_QUERY = N'UPDATE #TEMP_TABLE SET BLOCK_1 = #VALUE WHERE ID = 12';
EXEC sp_executesql #SQL_QUERY, N'#VALUE nvarchar(max)', #HtmlValue;
Note: The way to debug dynamic SQL is by using the PRINT statement, which if you run on your original SQL gives:
UPDATE TEMP_TABLE SET
BLOCK_1 = иĆÊô￴∀⠢Ĉ!ࠀސȁސ﷿ ױ﹗£΀ਮշωԊӍԊӍ̳¡﹩fȒ@† ™ IJ囌垐輈׶č靀ミ
WHERE ID = 12
Which is clearly wrong, you need:
UPDATE TEMP_TABLE SET
BLOCK_1 = N'иĆÊô￴∀⠢Ĉ!ࠀސȁސ﷿ ױ﹗£΀ਮշωԊӍԊӍ̳¡﹩fȒ@† ™ IJ囌垐輈׶č靀ミ'
WHERE ID = 12

how to find a particular string in the sentence and remove the string in sql

I have to remove the particular value from the sentence which is stored in SQL database. Sentence will look like this:
1 Payments:ihj - CHENNAI-HIRE:54005-TN69AZ54008,4021-TN69AZ54005
2 Payments:ihj - CHENNAI-HIRE:54004-TN69AZ54008,4021-TN69AZ54005,54005-TN69AZ54008
In above sentence 54004 is the number which I will pass as parameter to SQL. This is the number which I want to remove from this line but same number is present in this line as TN69AZ54005. This number should not be disturbed, and in another payment we have same amount in another place. Can anyone help on this?
I tried with this sql query
declare #text int=4019
select SUBSTRING(notes,CHARINDEX(cast(#text as varchar),notes),
len(notes)-CHARINDEX(',',notes)+1)
from Accounts.TransactionNotes
where TransactionID=1978
If I use this query it will affect including this line TN69AZ54005
I can see that you've included a C# tag into your question. Then probably the easiest way is just to select all necessary rows using your app, then iterate through them and change the strings to your needs (using eg. PHP preg_replace() equivalent) and update the SQL rows.
I believe that is the easiest way, not really SQL solution but still...
update <table> set notes = replace(notes, 'HIRE:'+ str(<inputparam>),'HIRE:') where transactionid=<transactionid>
update <table> set notes = replace(notes, ','+ str(<inputparam>),',') where transactionid=<transactionid>
You will need to find something to prefix your inputpram value, like in above example I am using "HIRE:" or a comma.
Another way could be to use REGEXP to find the whole word, then one one query would suffice. But I haven't tried it.
The problem here is not the query but the person who designed the
database.
I`m not sure is it this what you want but I will past my code. :)
-- for test create #temp
SELECT
A.DATA
INTO #Temp
FROM
(
SELECT 'Payments:ihj - CHENNAI-HIRE:54005-TN69AZ54008,4021-TN69AZ54005' AS DATA
UNION
SELECT 'Payments:ihj - CHENNAI-HIRE:54004-TN69AZ54008,4021-TN69AZ54005,54005-TN69AZ54008' AS DATA
) AS A
GO
-- this you want?
UPDATE #Temp
SET DATA = REPLACE(DATA,'54004','')
GO
-- select changed data
SELECT * FROM #Temp

Why is NPoco ignoring column and property names and mapping almost randomly?

I'm using the NPoco ORM (a branch of PetaPoco) but I've just noticed it's mapping the columns incorrectly in some cases.
I'm using a stored procedure and my POCO property names are identical to the column names produced by the stored procedure:
string sql = "EXEC API_GetVenueSummaryByID ##venueID = #venueID";
var venue = db.FirstOrDefault<VenueSummary>(sql, new { venueID = venueID });
The stored procedure is a simple SELECT statement with a couple of variables included (removing them doesn't help):
DECLARE #hasOffers bit
IF EXISTS(SELECT * FROM Offers WHERE dbo.Offers.EntryType='V' AND Offers.EntryID = #VenueID AND GETDATE() <= validToDate) SET #hasOffers = 1
SELECT
Venue.VenueID, VenueName, Town, County, Country, PackageCode,
MeetingRoomsNo, MaxMeetingCapacity, BedroomsNo,
MetaDescription AS ShortDescription,
'dummyresult.jpg' AS PrimaryImageFilename,
#hasOffers AS HasSpecialOffers,
CAST(TimeStamp AS BIGINT) AS RecordVersion
FROM dbo.Venue
WHERE Venue.VenueID = #VenueID
Is there a function in NPoco which causes it to guess the mappings (ignoring their names)? If so, how I can I disable this and force it to only match based on the column and property names?
Currently the only work around seems to be to use the column attribute <-- doesn't work either
At the moment, even someone auto-formatting stored procedure (or any change which results in a change of column order) is breaking the application.
Edit 2
I've noticed that if I restart the website application (eg by editing web.config or updating application code) then the column order fixes itself. So I can only assume the problem is related to NPoco internally caching the column indexes - and if the indexes change, the mappings will then be incorrect. I'm not sure if there's a mechanism to clear the cache that's perhaps not working?
This is a problem with how NPoco (and PetaPoco) caches the codegen that is used to map from a SQL statement to a POCO.
Usually this isn't a problem if you are changing the code when you are changing the SQL as the cache will be rebuild, however if you create your POCO first then start to change the SP after the first initial run the mappings will be incorrect.
This issues has now been fixed in 2.5.83-beta, and it will now look at the column names and their positions to determine the cache key.
Thanks for the help #NickG

Entity Framework Code First String Comparison with Oracle Db

I'm having trouble doing case insensitive string comparison using code first against an Oracle db. Code looks something like this;
String filter = "Ali";
var employee = dbContext.Employees.Where(x => x.Name.Contains(filter)).FirstOrDefault();
The code above acts to be case sensitive. So I converted both the Name and filter to Uppercase;
String filter = "Ali";
filter = filter.ToUpper();
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filter)).FirstOrDefault();
Everything seemed to work at first, but then I realized it's not working when the employee's name or the filter contains the character 'i'. The problem is how the letter i works in Turkish.
In most languages, 'i' stands for the lowercase, and 'I' stands for the uppercase version of the character. However in Turkish, 'i's uppercase is 'İ', and 'I's lowercase is 'ı'. Which is a problem as Oracle uppercases the letter 'i' in the db as 'I'.
We do not have access to the db's character encoding settings as its effects cannot be foreseen easily.
What I've come up with is this, and it is very ugly.
String filterInvariant = filter.ToUpper(CultureInfo.InvariantCulture);
String filterTurkish = filter.ToUpper(CultureInfo.CreateSpecificCulture("tr-TR"));
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filterInvariant) || x.Name.ToUpper().Contains(filterTurkish)).FirstOrDefault();
It seems to fix some of the issues, but feels like a brute force workaround rather than a solid solution. What are the best practices, or alternatives to this workaround, while using Code First C# against an Oracle database?
Thanks in advance
Ditch using all the UPPER functions. Simply let Oracle do your language aware case-insensitive matching. This is done by setting your DB connection from C# to have the appropriate language parameters. This setting is just for your DB session, not a global change for the whole DB. I'm no C# wizard, so you'd have to figure out where to make these session settings in your db connection/pool code.
ALTER SESSION SET nls_language=TURKISH;
ALTER SESSION SET nls_comp=LINGUISTIC;
ALTER SESSION SET nls_sort=BINARY_CI;
If C# proves too difficult to find where to change this, you could set this up as a user/schema logon trigger (below), which sets these automatically for you at db connect time (replace SOMEUSER with your actual db username). This only affects any NEW db sessions, so if you have connections pooled, you'll want to cycle the DB connection pool to refresh the connections.
CREATE OR REPLACE TRIGGER SOMEUSER.SET_NLS_CASE_INSENSITIVE_TRG AFTER
LOGON ON SOMEUSER.SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_language=TURKISH';
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_comp=LINGUISTIC';
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_sort=BINARY_CI';
END;
/
Here's a little test I did in an Oracle DB:
CREATE TABLE mypeople (name VARCHAR2(10 CHAR));
INSERT INTO mypeople VALUES ('Alİ Hassan');
INSERT INTO mypeople VALUES ('AlI Hassan');
INSERT INTO mypeople VALUES ('Ali Hassan');
INSERT INTO mypeople VALUES ('Alı Hassan');
SELECT name FROM mypeople WHERE name LIKE 'Ali%';
NAME
----------
Ali Hassan
ALTER SESSION SET nls_language=TURKISH;
ALTER SESSION SET nls_comp=LINGUISTIC;
ALTER SESSION SET nls_sort=BINARY_CI;
SELECT name FROM mypeople WHERE name LIKE 'Ali%';
NAME
----------
Alİ Hassan
AlI Hassan
Ali Hassan
The implementation of String.Contains is different for different providers, for example Linq2Sql is always case insensitive. The search is case sensitive or not depends on server settings. For example SQL Server by default has SQL_Latin1_General_CP1_CI_AS Collation and that is NOT case sensitive. For Oracle you can change this behavior at the session level: Case insensitive searching in Oracle (Issue a raw SQL query using context.Database.ExecuteSqlCommand method at the beginning of the session)
The problem is in the database, not in .NET, for example this query:
FILES.Where(t => t.FILE_NAME.ToUpper() == "FILE.TXT") // Get rows from file-table
translates into this Oracle SQL with the oracle provider I have:
SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
FROM FILES t0
WHERE (UPPER(t0.FILE_NAME) = :p0)
-- p0 = [FILE.TXT]
The contains with First() becomes this:
SELECT * FROM (SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
FROM FILES t0
WHERE ((UPPER(t0.FILE_NAME) LIKE '%' || :p0 || '%')
OR (UPPER(t0.FILE_NAME) LIKE '%' || :p1 || '%')))
WHERE ROWNUM<=1
-- p0 = [FILE.TXT]
-- p1 = [FİLE.TXT]
So it depends on your database's culture settings, ie without knowing them I would say the "overlap" with your solution is the best way to solve it. Why can't you just check the database culture settings?

Send a empty DateTime value into SQL stored procedure. But not null

I have an SQL stored procedure which accepts a DateTime parameter which has a default value of NULL
#pmNext_Check_Date DATETIME=NULL
I want to use this parameter in 3 scenarios:
If it's NULL then don't update any records
If it's got a date value then update all my records specified in my WHERE clause
The problem one! Set all the date fields in my query to NULL for the records in my WHERE clause.
Here is the block of code within the SP that is causing me issues (the rest of the UPDATE statement is build elsewhere in the SP and works fine):
IF #pmNext_Check_Date IS NOT NULL
IF #pmNext_Check_Date ='' --This is the bit that is causing me a problem. I just need to check for a empty date
SET #sql = #sql + ' Next_Check_Date = NULL '
ELSE
SET #sql = #sql + ' Next_Check_Date = #pmNext_Check_Date '
SET #sql = #sql + ' WHERE ID IN (1, 2)'
So for example if I have the following 2 rows:
ID NextCheckDate
1 12/12/12
2 NULL
In scenario 1 I wouldn't pass the parameter in as the procedure will use the default value and no dates will be updated.
In scenario 2 I pass in a date value and update both rows with the date value
In scenario 3 I want to update the date value on my rows to be null. The difference between scenario 1 & 3 is in scenario 3 the user will be choosing to set the date values to null.
So, I wanted to pass a blank date into the stored procedure. I'm doing this from C# and would like to do something like the following:
SqlParameter param = new SqlParameter("#pmNext_Check_Date", "");
This fails as the SP is expecting a DateTime.
So I want to be able to pass in a blank date and also how do I check this within the SP. The current check which is below doesn't work:
IF #pmNext_Check_Date =''
Thanks in advance.
Hope this all makes sense.
I'm using C#4.0 and SQL 2008
There is no such thing as a "blank date". You could use a well-known sentinel value (01 Jan for some arbitrary ancient year, for example), but null would be preferable. Note that to pass an explicit null via a parameter, you need:
SqlParameter param = new SqlParameter("#pmNext_Check_Date", DBNull.Value);
If that doesn't have enough granularity, consider adding a separate boolean (bit) parameter (or similar) that clarifies what you want the sproc to do. Or: have multiple procs to do these different things.
One useful sentinel value for SQL Server is January 1, 1753 (SQL Server's minimum datetime value) - this can be produced in TSQL without string parsing as cast(-53690 as datetime).
You can't pass an empty string as a datetime. So, you have a couple options. You could add an additional parameter to indicate whether or not an update should occur. I suggest that as the best options for code readability and maintainability. The other option would be to pass in the parameter as a string and parse it. That way you could use your empty string concept.
Sql Server string to date conversion
Sorry, there is no way to do precisely what you're asking. A DATETIME value is either NULL or a valid date, there is no "empty" like there is with strings.
Another workaround is to pass a token value (that wouldn't be a valid date otherwise) to represent your so-called empty string, e.g. a common one I've seen used is 1900-01-01. Then you can differentiate in your stored procedure between NULL and "empty."
But I don't recommend doing this at all. I agree with the other suggestions: add another parameter and do the logic in a more meaningful way in the stored procedure.
If I can recall correctly, columns with a DATETIME datatype which allow NULLS
will default to the value 1900-01-01 instead of a BLANK value.
For example:
NULLS may be allowed for certain columns which might receive a value later down the line based on some kind of business logic. I have seen folks keep these open ended columns as varchar to enable a custom entry of some type or an empty string, something which datetime will not allow.
If you ask me I'd try not to mess around with the base column's data type and let it remain as DATETIME. For data retrieval and reporting purposes we might try the following approach, which may not be the best way to do it. But it works.
BEGIN
DECLARE #VarcharDateTable TABLE
([EndDate_Varchar] varchar(27))
BEGIN
INSERT INTO #VarcharDateTable([EndDate_Varchar])
SELECT
CONVERT(varchar(27), [EndDate_Datetime], 121)
FROM [dbo].[MainTable]
END
BEGIN
SELECT CASE WHEN [EndDate_Varchar] LIKE '1900-01-01%'
THEN 'Data unavailable'--or whatever you want
ELSE [EndDate_Varchar]
END AS [EndDate_Varchar] FROM #VarcharDateTable
END
END

Categories