SqlDataSource SelectCommand с использованием LIKE не работает

У меня есть следующий T-SQL в SelectCommand:

SELECT h.Business,
hrl.frn
FROM registration hrl
INNER JOIN holder h on h.call = hrl.call
WHERE 
(h.Business like '%' + @business + '%' and h.Business is not null) 
and 
(hrl.frn = @frn and hrl.frn is not null)

business и frn связаны с параметрами управления, и он должен возвращать данные, даже если один или оба оставлены пустыми, но если я введу данные только для frn, например, он ничего не вернет. Я думаю, что мой T-SQL работает неправильно, и я также не уверен, правильно ли я обрабатываю like.

если оба текстовых поля оставлены пустыми, он должен вернуть все данные. Если frn введено, а business оставлено пустым, должны возвращаться только данные, относящиеся к этому frn. Если business введено, а frn оставлено пустым, должны быть возвращены все совпадения like business. Если оба введены, он должен возвращать данные, соответствующие только frn и business.

Кроме того, я не уверен, действительно ли необходимо делать and is not null.

protected void btnSearch_Click(object sender, EventArgs e)
{
    if (txtFRN.Text == "")
        frn = null;

    if (txtBusiness.Text == "")
        business = null;

    sqlDsMaster.SelectParameters[frn].DefaultValue = frn;
    sqlDsMaster.SelectParameters[business].DefaultValue = business;

    sqlDsMaster.DataBind();
}

Приведенное выше выдает «Ссылка на объект, не установленную в экземпляр», когда она попадает в эту строку:

sqlDsMaster.SelectParameters[frn].DefaultValue = frn;

frn и business являются свойствами.


Вот хранимая процедура SearchMaster:

CREAETE PROCEDURE SearchMaster
@business nvarchar(300) = NULL,
@frn nvarchar(10) = NULL
AS
SELECT h.Business,
       hrl.frn
FROM registration hrl
INNER JOIN holder h on h.call = hrl.call
WHERE (@business IS NULL OR h.Business like '%' + @business + '%') 
  AND (@frn IS NULL OR hrl.frn = @frn)

Вот хранимая процедура SearchDetails:

CREATE PROCEDURE SearchDetails
@business nvarchar(300) = NULL,
@frn nvarchar(10) = NULL
AS
SELECT hrl.call 
FROM registration hrl 
INNER JOIN holder h ON h.call = hrl.call
WHERE (@business IS NULL OR h.Business LIKE '%' + @business + '%') 
      AND (@frn IS NULL OR hrl.frn = @frn)

Вот SqlDataSource для процедуры SearchMaster:

<asp:SqlDataSource ID="sqlDsDetails" 
                   runat="server" 
                   ConnectionString="<%$ ConnectionStrings:cnxString %>
                   SelectCommandType="StoredProcedure" 
                   SelectCommand="SearchMaster">
  <SelectParameters>
    <asp:ControlParameter Name="business" ControlID="txtBusiness" 
                          Type="String" PropertyName="Text"  
                          ConvertEmptyStringToNull="true" />
    <asp:ControlParameter Name="frn" ControlID="txtFRN" 
                          Type="String" PropertyName="Text"
                          ConvertEmptyStringToNull="true"/>
  </SelectParameters>
</asp:SqlDataSource>

Вот SqlDataSource для процедуры SearchDetails:

<asp:SqlDataSource ID="sqlDsDetails" 
                   runat="server" 
                   ConnectionString="<%$ ConnectionStrings:cnxString %>
                   SelectCommandType="StoredProcedure" 
                   SelectCommand="SearchDetails">
  <SelectParameters>
    <asp:Parameter Name="frn" Type="String" DefaultValue="" 
                   ConvertEmptyStringToNull="true" />
    <asp:Parameter Name="business" Type="String" DefaultValue="" 
                   ConvertEmptyStringToNull="true" />
  </SelectParameters>
</asp:SqlDataSource>

Вот кнопка, которая связывает SqlDsMaster:

protected void btnSearch_Click(object sender, EventArgs e)
{
    sqlDsMaster.DataBind();
}

Вот gvMaster_RowCreated, который создает строки для деталей:

protected void gvMaster_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        SqlDataSource ctrl = 
        e.Row.FindControl("sqlDsDetails") as SqlDataSource;

        if (ctrl != null && e.Row.DataItem != null)
        {
            ctrl.SelectParameters["frn"].DefaultValue = 
            ((DataRowView)e.Row.DataItem)["frn"].ToString();

            ctrl.SelectParameters["business"].DefaultValue = 
            ((DataRowView)e.Row.DataItem)["business"].ToString();
         }
     }
 }

SearchMaster и SearchDetails оба работают, если я запускаю их через SQL Server Management Studio, и они работают, если я ввожу оба данных для business и frn, но если я ввожу только один, данные не возвращаются. Правильно ли выставлены параметры? Кроме того, если я инициализирую параметры null в процедуре, нужно ли использовать ConvertEmptyStringToNull?


person Xaisoft    schedule 26.03.2009    source источник
comment
Будьте осторожны, начиная строки с «%», так как это означает, что вы не сможете использовать индексы в отфильтрованном столбце.   -  person Steve Weet    schedule 27.03.2009
comment
Уточните, что вы имеете в виду. В этом случае у меня нет выбора, я должен использовать LIKE   -  person Xaisoft    schedule 27.03.2009


Ответы (3)


Я бы сделал что-то вроде:

where (@business is null
          or @business = ''
          or h.Business like '%' + @business + '%')
      and (@frn is null
              or @frn = ''
              or hrl.frn = @frn)

Если вы сделаете пустые строки поиска нулевыми перед их передачей, вы можете пропустить часть @yyy = ''.

person tvanfosson    schedule 26.03.2009
comment
Не могли бы вы рассказать об этом немного подробнее? Спасибо! - person Xaisoft; 27.03.2009
comment
Этот формат был предложен мне некоторое время назад в вопросе, и он работал безупречно. Я бы рекомендовал сначала проверить пустую строку, так как это делает окончательный запрос более читаемым. - person Dillie-O; 27.03.2009
comment
О, вопрос, который я упомянул, находится здесь: « title = «как создать хранимую процедуру, которая будет дополнительно искать столбцы»> stackoverflow.com/questions/205526/ - person Dillie-O; 27.03.2009
comment
Хорошо, я проверю это. Например, у меня есть TextBox с именем txtFRN, и я просто настраиваю ‹asp:ControlParameter›. Есть ли способ установить для @frn значение null, если txtFRN пуст. - person Xaisoft; 27.03.2009
comment
Я просто устанавливаю SelectParameters[frn] = null - person Xaisoft; 27.03.2009
comment
Используйте ConvertEmptyStringToNull = true. - person tvanfosson; 27.03.2009
comment
Можете ли вы привести пример? Я обновлю свой пост о коде, который у меня есть, но он не сработал, он выдал исключение - person Xaisoft; 27.03.2009
comment
Я не думаю, что вам нужно устанавливать их в коде. Вы должны иметь возможность настроить параметр управления в вашей разметке. Как выглядит конфигурация источника данных в разметке? - person tvanfosson; 27.03.2009
comment
Хорошо, я установил свойство ConvertEmptyStringToNull = true для ControlParameter в разметке. - person Xaisoft; 27.03.2009
comment
Стив прокомментировал мой вопрос: Будьте осторожны, начиная строки с «%», так как это означает, что вы не сможете использовать индексы в отфильтрованном столбце. Хотя не уверен, что он имел в виду. - person Xaisoft; 27.03.2009
comment
@Xaisoft - разница между начинается с и содержит. Если вы начинаете с запроса (без начального %), то он может просматривать индекс и проверять только записи с начальным символом. Если вы делаете contains, вы заставляете его выполнять сканирование таблицы, поскольку ему нечего индексировать. - person tvanfosson; 27.03.2009
comment
В итоге я создал две процедуры: SearchMaster и SearchDetails. Когда я запускаю процедуры в студии управления сервером sql, все работает нормально, но в коде это не так, я опубликую обновление в своем посте. - person Xaisoft; 27.03.2009

Изменять

"и ч.Бизнес не нулевой"

to

"или h.Business is null"

а также

"и hrl.frn не равен нулю"

to

"или hrl.frn имеет значение null"

Это вернет все, когда эти параметры равны нулю.

person Moose    schedule 26.03.2009

"and is not null"

В хранимых процедурах это правильно: (@frn IS NULL OR hrl.frn = @frn). Вы хотите выбрать любую строку, если frn равно null, или она совпадает. Тот же шаблон применим к свойству business.

NullReferenceException

sqlDsMaster.SelectParameters[frn].DefaultValue = frn;

Это не удается, потому что вы используете значение свойства frn (которое может быть null) вместо строки "frn" в качестве индекса в SelectParameters. У вас такая же ошибка в следующей строке с business вместо "business".

Конвертироватьпустотстрингтонулл

Я бы поставил вопрос наоборот: если вы используете ConvertEmptyStringToNull, зачем вам обременять вызывающую программу той же функциональностью? Если пустая строка не будет допустимым значением для frn или business, я бы оставил ConvertEmptyStringToNull установленным и не заботился об этом в вызывающем объекте.

Я надеюсь, что ответил на все ваши вопросы.

person David Schmitt    schedule 12.05.2009