Избегайте двойных кавычек в SQL 2005/2008 - PullRequest
2 голосов
/ 22 декабря 2008

У меня есть недавно добавленная международная компания, которая называется "BLA" BLAHBLAH "Ltd. (двойные кавычки являются частью названия.)

Всякий раз, когда пользователь пытается найти эту компанию, введя «Бла или что-то в этом роде», поиск завершается неудачей с синтаксической ошибкой на сервере SQL.

Как мне избежать этого, чтобы поиск не завершился неудачей?

Пример SQL:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH*' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC

Ответы [ 8 ]

7 голосов
/ 22 декабря 2008

К сожалению, двойные кавычки имеют особое значение внутри FTI, поэтому даже если вы их параметризуете, механизм FTI обрабатывает его как разделитель фраз. Я не уверен, что есть простой способ включить двойные кавычки в поиск FTI. Скобки также являются специальными символами, но их можно заключать в кавычки, чтобы рассматривать их как запрос, но не в двойных кавычках AFAIK.

Обновление

Немного поиска показывает, что удвоение кавычки к "" может исправить это - стоит попробовать. Лично я бы сделал это внутри БД, так как это деталь реализации TSQL.

Аналогично, «необходимо удвоить до» перед переходом в FTI (полностью отделенный от экранирования TSQL),

7 голосов
/ 22 декабря 2008

Используйте параметризованный запрос, и все ваши проблемы с цитированием исчезнут.

Редактировать: Если вы не позволяете им вводить более одного слова в СОДЕРЖАНИИ, очистите параметр, удалив кавычки. Очистка ввода путем удаления кавычек может работать в любом случае, независимо от поиска по нескольким словам.

3 голосов
/ 22 декабря 2008

Я сильно подозреваю, что вы строите SQL динамически - например,

// Bad code, do not use!
string sql = "SELECT * FROM Foo WHERE X LIKE '" + input + "%'";

Это очень, очень плохая идея по многим причинам, в частности Атаки SQL-инъекций . Вместо этого используйте параметризованные операторы SQL, в которых параметры указываются отдельно.

Посмотрите на различные ответы на вопросы с тегом sql-инъекций , чтобы найти примеры того, как это сделать правильно.

1 голос
/ 23 декабря 2008

Это немного теоретический ответ, но, возможно, это поможет. Краткая версия - «использовать параметры в запросе», но она помогает понять все детали.

В стандартном SQL строки заключаются в одинарные кавычки, а встроенные одинарные кавычки представлены двумя одинарными кавычками в строке:

SELECT * FROM SomeWhere
    WHERE SomeThing = 'He said, "Don''t do it!"';

В некоторых диалектах SQL вместо этого вы можете закрывать строки в двойных кавычках; Затем вам нужно удвоить двойные кавычки, чтобы вставить один экземпляр двойной кавычки:

SELECT * FROM SomeWhere
    WHERE SomeThing = "He said, ""Don't do it!""';

Из вопроса неясно, включает ли название компании внешние двойные кавычки, а также средние или просто содержит средние. Однако в принципе правила одинаковы. Предполагая, что все три двойные кавычки являются обязательными, и используя одинарные кавычки в SQL - намного проще в этом контексте:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  '"BLAH "BLAHBLAH" Ltd.' )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

Использование двойных кавычек:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect
    FROM RussoundGeneral.dbo.Company c  
         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm
                ON (cm.companyId = c.companyId and cm.maxID is not null)  
    WHERE CONTAINS ( companyName,  """BLAH ""BLAHBLAH"" Ltd." )
    GROUP BY c.companyID, c.companyName, c.dateAdded  
    ORDER BY c.companyName ASC;

Если вы строите строки на языке программирования, вам нужно беспокоиться о том, чтобы эти кавычки не проходили через все строки в вашем языке программирования. Например, если вы строите строковый литерал в C, вы должны будете избегать двойных кавычек с обратной косой чертой:

static const char sql_stmt[] =
"SELECT c.companyID, c.companyName, c.dateAdded,\n"
"       COUNT(cm.maxID) AS NumDirect\n"
"    FROM RussoundGeneral.dbo.Company c\n"
"         LEFT JOIN RussoundGeneral.dbo.CompanyMax cm\n"
"                ON (cm.companyId = c.companyId AND cm.maxID IS NOT NULL)\n"  
"    WHERE CONTAINS(companyName,  \"\"\"BLAH \"\"BLAHBLAH\"\" Ltd.\")\n"
"    GROUP BY c.companyID, c.companyName, c.dateAdded\n"
"    ORDER BY c.companyName ASC";

С другой стороны, если вы читаете данные от пользователя, например, название компании, вы просто должны убедиться, что прочитанное правильно указано в кавычках.

Те, кто сказал «использовать параметры», правы: это намного проще и надежнее, и менее уязвимо для атак с использованием SQL-инъекций (см. XKCD , если вы еще этого не видели). Но если вы понимаете основы, вы можете адаптироваться к фактическим требованиям вашей системы.

Последнее замечание: в стандартном SQL двойные кавычки заключают в себе «идентификаторы с разделителями». То есть двойные кавычки окружают имя, которое должно рассматриваться как имя чего-либо в базе данных, а не как строковый литерал. В MS SQL Server [квадратные скобки] служат той же цели; то, что находится в скобках - это имя столбца или что-то еще внутри базы данных. Многие системы более гибкие, чем это; не все системы одинаковы в том, как они отличаются от стандарта.

0 голосов
/ 23 декабря 2008

Вам, наконец, придется извлечь данные из вашей базы данных и отобразить их на экране или распечатать в отчетах. Манипулирование двойными кавычками или дополнительным символом может привести к путанице.

Преобразуя строки в HTML перед INSERTS или UPDATES, вы избегаете путаницы, связанной с управлением цитатами. В ВЫБОР времени будет легко конвертировать обратно из HTML. Во время отчетности (поскольку инструменты отчетности (такие как Crystal Reports) предлагают вариант форматирования HTML), вам даже не нужно будет ничего делать для правильного отображения данных.

Кстати, не забудьте повесить парня, который придумал название этой компании.

0 голосов
/ 23 декабря 2008

должно быть что-то вроде

string sqlCommand = "SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect FROM RussoundGeneral.dbo.Company c LEFT JOIN RussoundGeneral.dbo.CompanyMax cm ON (cm.companyId = c.companyId and cm.maxID is not null ) WHERE CONTAINS ( companyName,  '@strVal' ) group by c.companyID, c.companyName, c.dateAdded ORDER BY c.companyName ASC"
SqlCommand command = new SqlCommand(strSQLCommand, conn); 
SqlCommand.Parameters.AddWithValue("@strval", SearchTextBox.Text); 
0 голосов
/ 22 декабря 2008

Попробуйте использовать ключевое слово escape:

SELECT c.companyID, c.companyName, c.dateAdded, count(cm.maxID) as NumDirect 
FROM RussoundGeneral.dbo.Company c          
LEFT JOIN RussoundGeneral.dbo.CompanyMax cm 
ON (cm.companyId = c.companyId and cm.maxID is not null )  
WHERE CONTAINS ( companyName,  '\"BLAH*' ) escape '\'
group by c.companyID, c.companyName, c.dateAdded  ORDER BY c.companyName ASC
0 голосов
/ 22 декабря 2008

Вы пытались заменить символ его ASCII-кодом?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...