2

I know this topic is all over the place, but I am not doing an INSERT, UPDATE, DELETE. My statement is a plain and simple SELECT statement and so far has worked with 116 different items in my database until I got to one.

I have a search engine and am going through every single product in our database to add information to it. This is all done through the website, but when I search for ProductID 331 and click on it, it goes to the error page that says Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

It doesn't make any sense to me that the website would error with only this one product. This is the statement I am using. Does anyone know why 1 product would be causing this error?

WebService:

Public Class ProductSearch
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function GetProducts(ByVal prefixText As String, ByVal count As Integer) 
                            As String()
    Dim ProductSql As String = "Select DISTINCT ProductID, ProductName 
                                FROM Product WHERE ProductName 
                                LIKE '%' & @prefixText & '%' 
                                ORDER BY ProductName ASC"
    Using sqlConn As New SqlConnection
     (System.Configuration.ConfigurationManager.ConnectionStrings
     ("LocalSqlServer").ConnectionString)
        sqlConn.Open()
        Dim myCommand As New SqlCommand(ProductSql, sqlConn)
        myCommand.Parameters.Add("@prefixText", SqlDbType.VarChar, 50)
                                 .Value = prefixText
        Dim myReader As SqlDataReader = myCommand.ExecuteReader()
        Dim myTable As New DataTable
        myTable.TableName = "ProductSearch"
        myTable.Load(myReader)
        sqlConn.Close()
        Dim items As String() = New String(myTable.Rows.Count - 1) {}
        Dim i As Integer = 0
        For Each dr As DataRow In myTable.Rows
            Dim id As String = dr("ProductID").ToString()
            Dim name As String = dr("ProductName").ToString()
            Dim item As String = AjaxControlToolkit.AutoCompleteExtender
                                .CreateAutoCompleteItem(name, id)
            items.SetValue(item, i)
            i += 1
        Next
        Return items
    End Using
End Function
End Class

The aspx page that calls the webservice:

<%@ Page Title="Product Search" Language="VB" MasterPageFile="~/MasterPage.master"
 AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="Default" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" 
 TagPrefix="asp" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
<script type="text/javascript">
function AutoCompleteClientMethod(source, eventArgs) {
    var value = eventArgs.get_value();
    window.location = ("/Product/Default.aspx?id=" + value)
} 
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="body" Runat="Server">


    <asp:ScriptManager ID="ScriptManager1" runat="server">
    <Services>
        <asp:ServiceReference Path="ProductSearch.asmx" />
    </Services>
</asp:ScriptManager>    


    <asp:TextBox ID="Search" runat="server" AutoComplete="off"></asp:TextBox>
    <asp:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server"
      TargetControlID="Search" ServicePath="~/ProductSearch.asmx" 
      ServiceMethod="GetProducts" MinimumPrefixLength="1" CompletionSetCount="120" 
      EnableCaching="true" OnClientItemSelected="AutoCompleteClientMethod">
    </asp:AutoCompleteExtender>
  </div><!--End of main div -->
</asp:Content>

UPDATE: 11/9/2011 - I have found a couple more records that have this problem. They are ProductID 331-335. I have no idea what is going on here. Could it be that those products don't really exist or that they have some kind of bug?

Here is a list of ProductIDs and their corresponding ProductNames that have this error:

122 'Managed account section of the Web Site'
331 'Elliott Wave Principle Key to Market Behavior'
332 'Targeting Profitable Entry & Exit Points'
333 'Essentials of Trading It's not WHAT You Think, It's HOW You Think'
334 'Exceptional Trading The Mind Game'
335 'Fibonacci Analysis'
Jamie
  • 1,579
  • 8
  • 34
  • 74
  • 3
    There is no subquery in that, are you certain that is the full query from your code? Side Issue : PrefixText would be better to also be a bound variable and not string concat, to avoid potential SQL Injection – Andrew Nov 08 '11 at 21:52
  • I don't have any subqueries which makes me wonder why this error is happening. The only thing I can think of is that the javascript function is pulling back more than one value when it is trying to redirect the user. – Jamie Nov 10 '11 at 15:31

3 Answers3

3

I assume this is the sub-select query, DISTINCT doesn't mean one result. You can use TOP 1 to guarantee one result, but it doesn't guarantee it is the one you want.

Select TOP 1 DISTINCT ProductID, ProductName 
FROM Product WHERE ProductName 
LIKE '%" & prefixText & "%' 
ORDER BY ProductName ASC
rick schott
  • 21,012
  • 5
  • 52
  • 81
3

Besides Rick's answer, I would add that you should never concatenate strings to form SQL statements. Use parametrized queries instead. String concatenation exposes you to SQL Injection attacks. Also, by using parametrized queries you may gain performance if the query plans can be reused.

See this other StackOverflow post for a good discussion regarding parametrized queries on VB.NET.

Community
  • 1
  • 1
Icarus
  • 63,293
  • 14
  • 100
  • 115
  • I wasn't sure how to parameterize the prefix text but a user on another post of mine from a while back actually had the answer that whole time. Hah. I updated it :) – Jamie Nov 09 '11 at 15:22
  • @jlg Don't be afraid to change some one else's code when you see it follows this dangerous patterns. The guy/gal who wrote the code originally is probably not with the company anymore and now you are in charge. It will make your life easier, too! Anyway, I am very glad you sorted it out ;) – Icarus Nov 09 '11 at 15:29
  • Yeah you're right. It's a little nerve wracking to change something that works the way it is, even if it is a mess. I have only been in the 'real world' for 5 months. I didn't learn enough in college so hopefully I won't be too behind for very much longer! – Jamie Nov 09 '11 at 15:31
0

I figured out what the problem is. For some reason, these problematic products have more than one value assigned to them in data fields that SHOULD have only one item. The database has been changed recently so that doesn't happen, but I guess these 5 products were already messed up and have now been found out.

Thanks for all the help guys! I wish I would've thought to check further into the database sooner. (There are about 15 tables, so it's usually what I think of to do last)

Jamie
  • 1,579
  • 8
  • 34
  • 74