开发者

How to rectify this query in SQL Server 2005

I have the a query which is union of two queries, the resulting query is returning duplicate records, I don't want duplicate records. I tried using DISTINCT but still getting the same result, can anybody help me fix this query?

I also want to know whether this query is safe from SQL injection... I'll be pasting my query below:

ALTER PROCEDURE [dbo].[sp_GetTrashListWithSorting] --'6dbf9a01-c88f-414d-8dd9-696749258cef', '6dbf9a01-c88f-414d-8dd9-696749258cef','DateTime ASC','0','30'
(
    @p_CreatedBy UNIQUEIDENTIFIER,
    @p_ToReceipientID UNIQUEIDENTIFIER,
    @p_SortExpression NVARCHAR(100),
    @p_StartIndex INT,
    @p_MaxRows INT
)
AS
    SET NOCOUNT ON;

    IF LEN(@p_SortExpression) = 0 
       SET @p_SortExpression ='DateTime DESC'

    DECLARE @Sql NVARCHAR(4000)

    SET @sql = 'SELECT ID, DateTime, Subject, CreatedBy, ToReceipientID, Status
                FROM (SELECT ID, 
                             DateTime, 
                             Subject, 
                             CreatedBy, 
                             ToReceipientID, 
                             Status,
                             ROW_NUMBER() OVER(ORDER BY '+ @p_SortExpression +') AS Indexing
                      FROM (SELECT ID,
                                   DateTime, 
                                   Subject, 
                                   CreatedBy, 
                                   ToReceipientID, 
                                   SenderStatus AS Status
                             FROM ComposeMail 
                             WHERE (CreatedBy = @p)
                               AND (SenderStatus = 7 OR SenderStatus = 8)
                             UNION
                             SELECT ID,
                                    DateTime, 
           开发者_Go百科                         Subject, 
                                    CreatedBy, 
                                    ToReceipientID, 
                                    ReceiverStatus As Status
                              FROM ComposeMail
                              WHERE (ToReceipientID = @p1) 
                                AND (ReceiverStatus = 7 OR ReceiverStatus = 8)) AS NewDataTable
            ) AS IndexTable
   WHERE 
       Indexing > @p2 AND Indexing<= (@p2+@p3)' 

   DECLARE @paramDefinition NVARCHAR(500)

   SET @paramDefinition = N'@p UNIQUEIDENTIFIER ,@p1 UNIQUEIDENTIFIER, @p2 INT, @p3 INT'

   EXEC sp_executesql @sql, @paramDefinition,
                @p = @p_CreatedBy,
                @p1 = @p_ToReceipientID,
                @p2 = @p_StartIndex ,
                @p3 = @p_MaxRows


1) I re-wrote your SQL as:

WITH trash_list AS (
SELECT cm.id,
       cm.datetime, 
       cm.subject,
       cm.createdby,
       cm.toreceipientid, 
       cm.senderstatus AS Status
  FROM COMPOSEMAIL cm
 WHERE cm.createdBy = @p
   AND cm.enderStatus IN(7, 8)
UNION
SELECT cm.id,
       cm.datetime, 
       cm.subject,
       cm.createdby,
       cm.toreceipientid, 
       cm.receiverstatus AS Status
  FROM COMPOSEMAIL cm
 WHERE cm.toreceipientid = @p1
   AND cm.receiverstatus IN (7, 8))
SELECT t.id,
       t.datetime, 
       t.subject,
       t.createdby,
       t.toreceipientid, 
       t.status
  FROM (SELECT tl.id,
               tl.datetime, 
               tl.subject,
               tl.createdby,
               tl.toreceipientid, 
               tl.status,
               ROW_NUMBER() OVER(ORDER BY '+ @p_SortExpression +') AS Indexing
          FROM trash_list tl
      GROUP BY tl.id,
               tl.datetime, 
               tl.subject,
               tl.createdby,
               tl.toreceipientid, 
               tl.status) t
 WHERE t.indexing BETWEEN @p2 AND (@p2+@p3)

...but if you still get duplicates, review the logic in the SELECT/UNION in the WITH clause.

Get it to work as normal SQL before turning it into dynamic SQL.

2) The query is not safe from injection attacks because you aren't handling single quotes when users can provide text:

IF LEN(@p_SortExpression)=0 
  SET @p_SortExpression ='DateTime DESC'

...should be:

IF LEN(@p_SortExpression)=0 
  SET @p_SortExpression ='DateTime DESC'
ELSE
  SET @p_SortExpression = REPLACE(@p_SortExpression, '''', '''''')


You do not need to queries and a union. Instead of these 2 lines (one per subquery)

                         WHERE (CreatedBy = @p)
                         WHERE (ToReceipientID = @p1) 

do this (in one query)

                         WHERE CreatedBy IN (@p, @p1)

Like this:

SELECT
      ID
    , DateTime
    , Subject
    , CreatedBy
    , ToReceipientID
    , Status
FROM (
      SELECT
            ID
          , DateTime
          , Subject
          , CreatedBy
          , ToReceipientID
          , SenderStatus AS Status
          , ROW_NUMBER() OVER (ORDER BY ' + @p_SortExpression + ') AS Indexing
      FROM ComposeMail
      WHERE CreatedBy IN (@p, @p1)
            AND (SenderStatus = 7
            OR SenderStatus = 8)
) AS IndexTable
WHERE Indexing > @p2
      AND Indexing <= (@p2 + @p3)

HOWEVER I am not sure I understand how you pass in values for @p or @p1

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜