【问题标题】:Refine Search SQL with Custom Pagination使用自定义分页优化搜索 SQL
【发布时间】:2013-02-16 18:30:51
【问题描述】:

使用 asp.net mvc 应用程序和 c#。我们正在开发一个搜索页面。

更新了我的答案。请在下面查看我自己的答案并提出建议

不幸的是 select into 在 sql azure http://blogs.msdn.com/b/sqlazure/archive/2010/05/04/10007212.aspx 中不起作用

帮帮我

我有下表来显示我的项目搜索结果

物品表

  • ITEMID、SHOPID、ITEMNAME、DESCRIPTION、PRICE、CATID

商店表

  • SHOPId、标题、CITYID、活动

城市表

  • CITYID、CITYName、REGIONID、CountryISO

分类表

  • CATID、CATNAME

这是我的搜索查询,它给出了给定条件的分页结果

DECLARE @unitItems INT=20
DECLARE @sortOrder INT=0
DECLARE @catId INT
DECLARE @search NVARCHAR (100)=''
DECLARE @REGIONID INT=0
DECLARE @cityId INT=0
DECLARE @maxPrice DECIMAL (10, 2)
DECLARE @page INT
DECLARE @currentDate DATETIME2 (0)
set @unitItems=20
set @catId=0
set @sortOrder=0
set @search=''
set @cityId=1
set @maxPrice=0
set @page=1
set @currentDate='2013-02-24 13:14:58.073'

;WITH itemresult AS (
  SELECT IT.ITEMID, IT.ITEMNAME, IT.DESCRIPTION, IT.PRICE,
  IT.CATID, C.CATNAME AS CATNAME,S.HEADER AS SHOPHEADER,CI.CITYNAME AS CITY, 
  ROW_NUMBER() OVER (ORDER BY IT.SHOWDATE DESC) AS RowNumber
  FROM ITEM AS IT INNER JOIN SHOP AS S ON IT.SHOPId = S.ShopId 
  INNER JOIN CITY AS CI ON CI.CITYID = S.CITYID
  INNER JOIN COUNTRY AS CY ON CI.COUNTRYISO = CY.COUNTRYISO 
  INNER JOIN REGION AS R ON CI.REGIONID = R.REGIONID 
  INNER JOIN CITY AS CI2 ON CI2.CITYID = @cityId 
  INNER JOIN CATEGORY AS C ON IT.CATID = C.CATID    

  WHERE S.ACTIVE = 1   

  GROUP BY IT.ITEMID, IT.ITEMNAME, IT.HEADER, IT.DESCRIPTION, IT.PRICE, 
  IT.CATID, IT.SHOWDATE,S.HEADER,C.CATNAME,CI.CITYNAME) 

  SELECT IT.*, CEILING(CAST(RN AS float) / @unitItems) AS UNITPAGES, RN AS UNITROWS 
  FROM itemresult IT 
  INNER JOIN (SELECT Max(RowNumber) AS RN FROM itemresult) SUBQ ON 1=1 
  WHERE IT.RowNumber BETWEEN (@page - 1) * @unitItems + 1 
  AND @unitItems * @page 

问题:

现在的问题是我们要在 UI 中添加新的更改。搜索 UI 现在将显示如下内容

第一个结果集 -->假设总共找到 230 条记录

您在 Fiddle 中看到的搜索结果

第二个结果集 -->来自 230 条记录的不同类别和计数

CatId、CatName、TotalCountInSearch

例如:1 本书 25 和 2 体育 43 和 8 其他 52。 显示我可以在 UI 中显示如下

  • 所有类别 (120)
  • 书籍 (25)
  • 运动 (43)
  • 其他 (52)

第三个结果集 -->不同的城市和来自 230 条记录的计数

CityId、CityName、TotalCountInSearch

用于在 UI 下方显示

  • 所有城市(10)
  • 钦奈 (4)
  • 班格罗尔 (3)
  • 其他 (3)

我如何检索这些计数和名称,如所有类别、书籍、 所有城市等?欢迎任何帮助或建议

Click and View SQL Fiddle here

我想根据搜索条件获取这些计数。希望从我的过程中检索这个作为另一个结果集

主要更新:

我在这里上传了所有架构和实际动态查询 https://github.com/Padayappa/SQLProblem/blob/master/PaginationIssue

【问题讨论】:

  • 问题不是很清楚。如果您可以显示给定小提琴的预期结果,那么您的要求将很容易理解?
  • 看起来和这个sqlfiddle.com/#!3/52bbb/61相似
  • 抱歉,既然您已经获得了所需的结果,那么这些查询有什么问题?您的意思是您需要一次性获得这 3 个结果集吗?
  • @Kaf,我希望所有 3 个结果集都在同一个过程中。我的意思是执行一个搜索程序应该返回搜索结果、城市计数、类别计数信息。我不是 SQL 方面的专家。这个查询是由一位同事写的,他离开了。我不知道在不影响性能的情况下获取城市、类别信息的效率如何
  • 我已经回答了这个问题,还添加了一些我认为对您有用的额外细节。前任;如何从SSMS/C#执行名为myStoredProcedure的新程序

标签: c# asp.net sql sql-server sql-server-2008


【解决方案1】:

这是根据类别检索计数

select 'All categories' catname, count(*) catcount from itemtable
union all
select catname, count(catid) catcount
from itemtable inner join categorytable on categorytable.catid = itemtable.catid
group by catname

这是根据城市检索计数

select 'All cities' cityname, count(*) catcount from itemtable
union all
select cityname, count(catid) catcount 
from itemtable inner join shoptable on itemtable.shopid = shoptable.shopid
inner join citytable on citytable.cityid = shoptable.cityid
group by cityname

【讨论】:

  • 我已经用 Fiddle 更新了。我希望返回相同的 SQL 查询。请检查小提琴sqlfiddle.com/#!3/52bbb/1我需要另一个结果集,根据搜索场景为我提供这些计数
  • 您的查询提供了整体的所有类别和城市。我需要从过滤的记录中匹配我的搜索参数
  • 更新了我的问题,提供了 50 分赏金的更多信息
【解决方案2】:

试试这个。我希望这能满足你的期望

CREATE VIEW vSequence AS
WITH itemresult AS (
  SELECT IT.ITEMID, IT.ITEMNAME, IT.DESCRIPTION, IT.PRICE,
  IT.CATID, C.CATNAME AS CATNAME,S.HEADER AS SHOPHEADER,CI.CITYNAME AS CITY,CI.CITYID,
  ROW_NUMBER() OVER (ORDER BY IT.SHOWDATE DESC) AS RowNumber
  FROM ITEM AS IT INNER JOIN SHOP AS S ON IT.SHOPId = S.ShopId
  INNER JOIN CITY AS CI ON CI.CITYID = S.CITYID
  INNER JOIN COUNTRY AS CY ON CI.COUNTRYISO = CY.COUNTRYISO
  INNER JOIN REGION AS R ON CI.REGIONID = R.REGIONID
  INNER JOIN CITY AS CI2 ON CI2.CITYID = 1
  INNER JOIN CATEGORY AS C ON IT.CATID = C.CATID

  WHERE S.ACTIVE = 1

  GROUP BY IT.ITEMID, IT.ITEMNAME, IT.HEADER, IT.DESCRIPTION, IT.PRICE,
  IT.CATID, IT.SHOWDATE,S.HEADER,C.CATNAME,CI.CITYNAME,CI.CITYID)

SELECT * FROM itemresult IT

GO

  SELECT IT.*, CEILING(CAST(RN AS float) / 20) AS UNITPAGES, RN AS UNITROWS
  FROM vSequence IT
  INNER JOIN (SELECT Max(RowNumber) AS RN FROM vSequence) SUBQ ON 1=1
  WHERE IT.RowNumber BETWEEN (1 - 1) * 20 + 1
  AND 20 * 1
GO
SELECT  IT.CATID,RS.CATNAME , CONVERT(varchar(10), SUM(CASE WHEN IT.CATID = CAT.CATID THEN 1 ELSE 0 END)) AS 'Count'
FROM vSequence RS INNER JOIN ITEM IT ON RS.CATID = IT.CATID
INNER JOIN CATEGORY CAT
ON IT.CATID = CAT.CATID GROUP BY IT.CATID,RS.CATNAME
GO
SELECT  CIT.CITYID,CITYNAME,CONVERT(varchar(10), SUM(CASE WHEN CIT.REGIONID =  REG.REGIONID THEN 1 ELSE 0 END)) AS 'Count'
FROM COUNTRY CON INNER JOIN REGION REG
ON CON.COUNTRYISO = REG.COUNTRYISO
INNER JOIN CITY CIT ON CIT.REGIONID =  REG.REGIONID
INNER JOIN  vSequence RS ON CIT.CITYID=RS.CITYID GROUP BY REG.REGIONID,CITYNAME, CIT.CITYID

SQL Fiddle 示例。

【讨论】:

    【解决方案3】:

    据我从您的 cmets 了解到,我认为您需要是获得 3 result sets by executing a single stored procedure。您还想知道查询是否已优化。

    我认为你的 vSequence VIEW 很好(所以,我没有在这里添加我的答案)。您需要create a stored procedure 获得三个不同的结果集using your view,如下所示。我已将您在小提琴中声明的变量列表作为存储过程的参数。我在每个变量旁边发表了评论。由于您的过滤要求尚不清楚,因此我将它们保留原样。

    CREATE PROCEDURE myStoredProcedure 
       @unitItems INT=20, --number of items per page
       @sortOrder INT=0, --not used
       @catId INT, --not in use 
       @search NVARCHAR (100)='', --not used
       @REGIONID INT=0, -- not used
       @cityId INT=0, -- not used
       @maxPrice DECIMAL (10, 2), -- not used
       @page INT, --page number
       @currentDate DATETIME2 (0) -- not used
    AS 
    BEGIN
    
        /*
          Query 1
          Note: I have assumed your @page start at 1 and also changed the where clause 
          to bring correct data based on @page & @unitItems parameters 
        */
        SELECT IT.*, CEILING(CAST(RN AS float) / 20) AS UNITPAGES, RN AS UNITROWS
        FROM vSequence IT INNER JOIN (SELECT Max(RowNumber) AS RN FROM vSequence) SUBQ ON 1=1
        WHERE IT.RowNumber BETWEEN (@unitItems * (@page - 1) + 1) AND @unitItems 
    
        /* Query 2 */
        SELECT  IT.CATID,RS.CATNAME , CONVERT(varchar(10), 
                SUM(CASE WHEN IT.CATID = CAT.CATID THEN    1 ELSE 0 END)) AS 'Count'
        FROM vSequence RS 
                  INNER JOIN ITEM IT ON RS.CATID = IT.CATID 
                  INNER JOIN CATEGORY CAT ON IT.CATID = CAT.CATID 
        GROUP BY IT.CATID,RS.CATNAME
    
        /* Query 3 */
        SELECT  CIT.CITYID,CITYNAME,CONVERT(varchar(10), 
                SUM(CASE WHEN CIT.REGIONID =   REG.REGIONID THEN 1 ELSE 0 END)) AS 'Count'
        FROM COUNTRY CON 
                 INNER JOIN REGION REG ON CON.COUNTRYISO = REG.COUNTRYISO
                 INNER JOIN CITY CIT ON CIT.REGIONID =  REG.REGIONID
                 INNER JOIN  vSequence RS ON CIT.CITYID=RS.CITYID 
        GROUP BY REG.REGIONID,CITYNAME, CIT.CITYID
     END
    

    下面是如何执行Management Studio中的存储过程(请使用适当的参数值):

    DECLARE @unitItems INT = 20, 
            @sortOrder INT = 0, 
            @catId INT = 0,
            @search NVARCHAR (100) = '', 
            @REGIONID INT = 0, 
            @cityId INT = 1,
            @maxPrice DECIMAL (10, 2) = 0,
            @page INT = 1,
            @currentDate DATETIME2 (0) = '2013-02-24 13:14:58.073'
    
    EXEC myStoredProcedure 
           @unitItems,
           @sortOrder,
           @catId,
           @search,
           @REGIONID,
           @cityId,
           @maxPrice,
           @page,
           @currentDate
    

    要在您的 C# 代码中执行此存储过程,请使用带有 DataAdapter 的参数化查询,如下所示:

    DataSet ds = new DataSet();
    using (SqlConnection connection =  new SqlConnection("your-Connection-String-here"))
    {
    
        SqlDataAdapter adapter = new SqlDataAdapter();
        adapter.SelectCommand = new SqlCommand("myStoredProcedure", connection);
        adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
        adapter.SelectCommand.Parameters.AddWithValue("@unitItems",20);
        //add other parameters as above here
        adapter.SelectCommand.Parameters.AddWithValue("@page",1); //correct page number
        adapter.Fill(ds);
    }
    
    //Now you can access all query results as 
    ds.Tables[0]; //results from query1
    ds.Tables[1]; //results from query2
    ds.Tables[2]; //results from query3
    

    【讨论】:

    【解决方案4】:

    最后我创建了下面的 SP 并解决了问题。

    请告诉我这是正确的方法吗?

    我使用了临时表、Grouping SETS、Grouping_ID

    你可以在这里看到代码https://github.com/Padayappa/SQLProblem/blob/master/PaginationResolved

     CREATE PROCEDURE [dbo].[Item_SearchItems_New]
     (
       @ShopNr INT
    ,@unitItems INT = 20
    ,@sortOrder INT = 0
    ,@language CHAR(2) = 'EN'
    ,@catId INT
    ,@search NVARCHAR(100) = ''
    ,@countryIso NCHAR(2) = ''
    ,@regionNr INT = 0
    ,@cityId INT = 0
    ,@maxPrice DECIMAL(10, 2)
    ,@page INT
    ,@currentDate DATETIME2(0)
    ,@distance NUMERIC(4, 1)
    ,@isFavoriteShop BIT = 0
    ,@currentUserNr INT = 0
    ,@latitude FLOAT(53) = 0
    ,@longitude FLOAT(53) = 0
    ,@itemType TINYINT = 0
    ,@unitRows INT OUTPUT
    ,@unitPages INT OUTPUT
     )
     AS
     BEGIN
    SET XACT_ABORT ON
    SET NOCOUNT ON
    
    DECLARE @sql NVARCHAR(MAX)
            ,@sqlSelect NVARCHAR(MAX) = ''
            ,@sqlTempTable NVARCHAR(MAX) = '#itemSearch'
            ,@sqlCountTempTable NVARCHAR(MAX) = '#itemCount'
            ,@sqlInto NVARCHAR(MAX) = ''
            ,@sqlFrom NVARCHAR(MAX) = ''
            ,@sqlClause NVARCHAR(MAX) = ''
            ,@sqlGroup NVARCHAR(MAX) = ''
            ,@params NVARCHAR(MAX)
            ,@citySearch bit = 0
            ,@gpsSearch bit = 0
            ,@sortOrderString NVARCHAR(MAX) = 'ORDER BY IT.CREATEDATE DESC'
            ,@sortOrderString2 NVARCHAR(MAX) = ''
    
    IF (@cityid <= 0) AND (@currentUserNr > 0) AND (@latitude = 0)
        SELECT  @cityid = CITYID
        FROM    USERINFO
        WHERE   USERNR = @currentUserNr
    ELSE IF (@cityid <= 0) AND (@latitude > 0)
        SET @gpsSearch = 1
    ELSE IF (@cityid > 0)
        SET @citySearch = 1
    
    
    
    IF (@sortOrderString2 = '')
        SET @sortOrderString2 = @sortOrderString
    
    IF (@unitItems = 0)
        SET @unitItems = 20
    
    IF (@page <= 0)
        SET @page = 1
    
    SET @sqlSelect =
        'SELECT     J.URLNAME
                    ,IT.ITEMNR
                    ,IT.USERNR
                    ,IT.ShopNR
                    ,IT.ITEMID
                    ,IT.ITEMNAME
                    ,IT.HEADER
                    ,IT.DESCRIPTION
                    ,IT.PRICE
                    ,IT.CREATEDATE
                    ,IT.ITEMSTATUS
                    ,IT.CURRENCYCODE
                    ,IT.CATID
                    ,IT.VISIT
                    ,IT.ENDDATE
                    ,IT.PREAMBLE
                    ,IT.SHOWDATE
                    ,IT.LASTUPDATED
                    ,C.CATNAME AS CATNAME
    
                    ,J.HEADER AS ShopHEADER
                    ,J.LATITUDE
                    ,J.LONGITUDE
                    ,R.REGIONNAME AS REGIONNAME
                    ,CY.COUNTRYISO
                    ,R.REGIONNR
                    ,CY.COUNTRYNAME AS COUNTRYNAME
                    ,CI.CITYNAME AS CITY
                    ,ROW_NUMBER() OVER (' + @sortOrderString + ') AS RowNumber'
    
    SET @sqlGroup =
        ' GROUP BY  J.URLNAME
                    ,IT.ITEMNR
                    ,IT.USERNR
                    ,IT.ShopNR
                    ,IT.ITEMID
                    ,IT.ITEMNAME
                    ,IT.HEADER
                    ,IT.DESCRIPTION
                    ,IT.PRICE
                    ,IT.CREATEDATE
                    ,IT.ITEMSTATUS
                    ,IT.CURRENCYCODE
                    ,IT.CATID
                    ,IT.VISIT
                    ,IT.ENDDATE
                    ,IT.PREAMBLE
                    ,IT.SHOWDATE
                    ,IT.LASTUPDATED
                    ,C.CATNAME
    
                    ,J.HEADER
                    ,J.LATITUDE
                    ,J.LONGITUDE
                    ,R.REGIONNAME
                    ,CY.COUNTRYISO
                    ,R.REGIONNR
                    ,CY.COUNTRYNAME
                    ,CI.CITYNAME'
    
    SET @sqlFrom =
        ' FROM      dbo.ITEM AS IT
        INNER JOIN  dbo.Shop AS J
                ON  IT.ShopNR = J.ShopNR
        INNER JOIN  dbo.CITY AS CI
                ON  CI.CITYID = J.CITYID
        INNER JOIN  dbo.COUNTRY AS CY
                ON  CI.COUNTRYISO = CY.COUNTRYISO
        INNER JOIN  dbo.REGION AS R
                ON  CI.REGIONNR = R.REGIONNR'
    
        SET @sqlFrom = @sqlFrom +
            ' INNER JOIN    dbo.CATEGORY AS C
                    ON  IT.CATID = C.CATID '
    
        SET @sqlClause =
            ' WHERE     J.ACTIVE = 1
                    AND IT.ITEMSTATUS = 1
                    AND IT.ENDDATE > @currentDate'      
    
        IF (@itemType = 1) 
            SET @sqlClause = @sqlClause +
                ' AND IT.ITEMTYPE = 1'
    
        IF (@catId > 0)
            SET @sqlClause = @sqlClause +
                ' AND (C.CATID = @catId OR C.PARENTCATID = @catId)'
    
        IF (@ShopNr > 0)
            SET @sqlClause = @sqlClause +
                ' AND IT.ShopNR = @ShopNr'
    
        IF (@search <> '') 
            SET @sqlClause = @sqlClause +
                ' AND ((IT.HEADER LIKE ''%' + @search + '%'') OR (IT.DESCRIPTION LIKE ''%' + @search + '%''))'
    
        SET @sqlInto = ' INTO ' + @sqlTempTable + ' ';
    
        SET @sql =  @sqlSelect +
                    @sqlInto +
                    @sqlFrom +
                    @sqlClause +
                    @sqlGroup
    
        SET @sql = @sql + ';
    
            SELECT  @unitRows = @@ROWCOUNT
                    ,@unitPages = (@unitRows / @unitItems) + 1;
    
            SELECT  *
            FROM    ' + @sqlTempTable + ' AS IT
            WHERE   RowNumber BETWEEN (@page - 1) * @unitItems + 1 AND @unitItems * @page
            ' + @sortOrderString2 + ';
    
            SELECT      CATNAME
                        ,CITY
                        ,COUNT(*) AS ITEMCOUNT
                        ,GROUPING_ID(CATNAME, CITY) AS ITEMCOUNTTYPEID
            INTO        '+ @sqlCountTempTable + '
            FROM        ' + @sqlTempTable + '
            GROUP BY    GROUPING SETS
                        (
                            (CATNAME)
                            ,(CITY)
                            ,()
                        )
    
            SELECT      ISNULL(CATNAME, ''All Categories'') AS CATNAME
                        ,ITEMCOUNT
            FROM        '+ @sqlCountTempTable + '
            WHERE       ITEMCOUNTTYPEID IN (1, 3)
            ORDER BY    ITEMCOUNTTYPEID DESC
                        ,CATNAME
    
            SELECT      ISNULL(CITY, ''All Cities'') AS CITY
                        ,ITEMCOUNT
            FROM        '+ @sqlCountTempTable + '
            WHERE       ITEMCOUNTTYPEID IN (2, 3)
            ORDER BY    ITEMCOUNTTYPEID DESC
                        ,CITY';
    
        SELECT @params =
            N'@language nchar(2), ' +
            N'@ShopNr int, ' +
            N'@cityId int, ' +
            N'@catId int, ' +
            N'@distance numeric(4,1), ' +
            N'@currentDate datetime, ' + 
            N'@unitItems int,' + 
            N'@countryIso nchar(2),' + 
            N'@regionNr int,' + 
            N'@page int,' + 
            N'@currentUserNr int,' +
            N'@latitude float,' +
            N'@longitude float,' +
            N'@unitRows int OUTPUT,' +
            N'@unitPages int OUTPUT'
    
    --print @sql
    
    EXEC    sp_executesql @sql
            ,@params
            ,@language
            ,@ShopNr
            ,@cityId
            ,@catId
            ,@distance
            ,@currentDate
            ,@unitItems
            ,@countryIso
            ,@regionNr
            ,@page
            ,@currentUserNr
            ,@latitude
            ,@longitude
            ,@unitRows OUTPUT
            ,@unitPages OUTPUT
    END
    GO
    
    
    DECLARE @unitPages INT
        ,@unitRows INT
    
    exec Item_SearchItems_New @ShopNr=0,@unitItems=20,@catId=0,@language='',@sortOrder=0,@search=default,@countryIso='in',
    @regionNr=2702259,@cityId=2702261,@maxPrice=0,@page=1,@distance=50,@currentDate='2013-02-24 19:29:50.623',@isFavoriteShop=0,
    @currentUserNr=0,@latitude=0,@longitude=0,@itemType=0,@unitRows = @unitRows OUTPUT, @unitPages = @unitPages OUTPUT
    
    SELECT  @unitPages, @unitRows
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      • 2018-09-10
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多