使用自定义分页优化搜索SQL

时间:2013-03-02 06:34:52

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

使用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,HEADER,CITYID,ACTIVE

城市表

  • 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中添加了新的更改。现在,搜索界面会显示如下所示的内容

第一个结果集 - >假设总共发现了230条记录

在小提琴中看到的搜索结果

第二个结果集 - >不同类别&从230条记录算起

  

CatId,CatName,TotalCountInSearch

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

  • 所有类别(120)
  • 书籍(25)
  • 体育(43)
  • 其他(52)

第三个结果集 - >不同城市&从230条记录算起

  

CityId,CityName,TotalCountInSearch

用于在UI中显示以下

  • 所有城市(10)
  • Chennai(4)
  • Banglore(3)
  • 其他(3)
  

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

Click and View SQL Fiddle here

我想根据搜索条件获得这些计数。希望从我的程序

中将其作为另一个结果集进行检索

主要更新:

  

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

4 个答案:

答案 0 :(得分:4)

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

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示例。

答案 1 :(得分:3)

根据我的评论,我认为需要 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

答案 2 :(得分:1)

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

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

  

我使用了临时表,分组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

答案 3 :(得分:0)

这是根据类别检索计数

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