选择结果的位置,上方或下方有其他行

时间:2018-08-16 05:07:09

标签: sql sql-server tsql sql-server-2016

这是示例表

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CypherCollectionViewCell", for: indexPath as IndexPath) as! CypherCollectionViewCell

    cell.tickButton.addTarget(self, action: #selector(tickButtonClicked(sender:)), for: .touchUpInside)

    return cell
}

@objc func tickButtonClicked( sender: UIButton) {

    var convertedPoint : CGPoint = sender.convert(CGPoint.zero, to: self. collectionView)
    var indexPath = self. collectionView.indexPathForItemAtPoint(convertedPoint)
    let cell = self. collectionView.cellForItemAtIndexPath(indexPath) as! CypherCollectionViewCell

    if sender.isSelected {
        sender.isSelected = false
        // To change the UIView border color
        cell.view.borderColor = UIColor.blue()
    } else {
       sender.isSelected = true
       // To change the UIView border color
        cell.view.borderColor = UIColor.red()
    }
}

这是选择结果查询,其中tglValid位于2个日期之间

SELECT NoPolisi, ComLocID, Jenis, TglValid, rn 
FROM  (
          SELECT NoPolisi, ComLocID, Jenis, TglValid, NoPolisiBaru,
                 ROW_NUMBER() OVER (PARTITION BY NoPolisi ORDER BY TglValid) rn 
          FROM MstData.dbo.Ms_UbahBentukArmada
      ) A
WHERE NoPolisi = 'BK 8819 CF'

上面的查询结果是

enter image description here

我的问题是,我能得到所选结果在上方还是下方有额外的一行,因此结果包含rn = 5行或rn = 2行?

编辑: 在它使用的@gotqn答案中

DECLARE 
    @DateFrom smalldatetime = '20170101',
    @DateTo smalldatetime = '20171201'
SELECT NoPolisi, ComLocID, Jenis, TglValid, rn 
FROM  (
          SELECT NoPolisi, ComLocID, Jenis, TglValid, NoPolisiBaru, 
                 ROW_NUMBER() OVER (PARTITION BY NoPolisi ORDER BY TglValid) rn 
          FROM MstData.dbo.Ms_UbahBentukArmada
      ) A
WHERE NoPolisi = 'BK 8819 CF' 
AND   TglValid BETWEEN @DateFrom AND @DateTo

但是如果日期范围在中间,如上面的代码 它必须返回第2行:

DECLARE @DataSource TABLE
(
     [id] INT
    ,[date] DATETIME2(0)
);

INSERT INTO @DataSource ([id], [date])
VALUES (100, '2000-01-01')
      ,(110, '2016-03-01')
      ,(120, '2017-06-06')
      ,(130, '2017-07-01')
      ,(140, '2018-01-01');

DECLARE 
    @DateFrom smalldatetime = '20170401',
    @DateTo smalldatetime = '20170430';

    WITH DataSource AS
(
    SELECT * 
          ,ROW_NUMBER() OVER (ORDER BY [date]) AS [rn]
          ,IIF
          (
            [date] BETWEEN @DateFrom AND @DateTo
            OR
            LAG([date]) OVER(ORDER BY [date]) BETWEEN @DateFrom AND @DateTo
            ,1
            ,0
           ) AS [in_interval]
    FROM @DataSource
)
SELECT *
FROM DataSource
-- WHERE [in_interval] = 1;

感谢帮助。

2 个答案:

答案 0 :(得分:2)

因此,您需要具备以下条件:

  • 最大rn小于最小输出数据rn
  • 最小的rn比最大的输出数据rn

rnSELECT phase中计算时,为了使用它,我们需要具体化结果。然后,使用UNION ALL使用WHERE [rn] = (SELECT MIN(rn) - 1 FROM data)WHERE [rn] = (SELECT max(rn) + 1 FROM data)添加所需的记录。

下面,我正在使用另一种使用self join的方法。因此,此查询:

DECLARE @DataSource TABLE
(
     [id] INT
    ,[date] DATETIME2(0)
);

INSERT INTO @DataSource ([id], [date])
VALUES (100, '2000-01-01')
      ,(110, '2016-03-01')
      ,(120, '2017-06-06')
      ,(130, '2017-07-01')
      ,(140, '2018-01-01');

DECLARE 
    @DateFrom smalldatetime = '20170101',
    @DateTo smalldatetime = '20171201';

WITH DataSource AS
(
    SELECT * 
          ,ROW_NUMBER() OVER (ORDER BY [date]) AS [rn]
          ,CASE WHEN [date] BETWEEN @DateFrom AND @DateTo THEN 1 ELSE 0 END AS [in_interval]
    FROM @DataSource
)
SELECT *
FROM DataSource DS1
LEFT JOIN DataSource DS2
    ON DS1.[rn] = DS2.[rn] - 1;

enter image description here

因此,您需要添加WHERE DS1.[in_interval] = 1 OR DS2.[in_interval] = 1。为了获得下一行,请从此更改ON子句:

ON DS1.[rn] = DS2.[rn] - 1

对此:

ON DS1.[rn] = DS2.[rn] + 1

或添加其他自连接以获取两行。


对于SQL Server 2012+,您可以使用LEADLAG函数来计算是否应包含行:

WITH DataSource AS
(
    SELECT * 
          ,ROW_NUMBER() OVER (ORDER BY [date]) AS [rn]
          ,IIF
          (
            [date] BETWEEN @DateFrom AND @DateTo
            OR
            LAG([date]) OVER(ORDER BY [date]) BETWEEN @DateFrom AND @DateTo
            ,1
            ,0
           ) AS [in_interval]
    FROM @DataSource
)
SELECT *
FROM DataSource
-- WHERE [in_interval] = 1;

我们需要添加其他列以计算范围内的行数。如果行中没有行,则使用UNION ALL提取一行:

  WITH DataSource AS
(
    SELECT * 
          ,ROW_NUMBER() OVER (ORDER BY [date]) AS [rn]
          ,IIF
          (
            [date] BETWEEN @DateFrom AND @DateTo
            OR
            LAG([date]) OVER(ORDER BY [date]) BETWEEN @DateFrom AND @DateTo
            ,1
            ,0
           ) AS [in_interval]
         ,SUM(IIF( [date] BETWEEN @DateFrom AND @DateTo, 1, 0)) OVER() valid_dates 
    FROM @DataSource
)
SELECT *
FROM DataSource
WHERE [in_interval] = 1
UNION ALL
SELECT *
FROM
(
    SELECT TOP 1 *
    FROM DataSource
    WHERE [date] < @DateFrom
        AND [valid_dates] = 0
    ORDER BY [rn] DESC
) DS

答案 1 :(得分:1)

感谢所有答案。 我想要的结果就是这样

DECLARE @DataSource TABLE
(
     [id] INT
    ,[date] DATETIME2(0)
);

INSERT INTO @DataSource ([id], [date])
VALUES (100, '2000-01-01')
      ,(100, '2016-03-01')
      ,(100, '2017-06-06')
      ,(100, '2017-07-01')
      ,(100, '2018-01-01');

DECLARE 
    @DateFrom smalldatetime = '20170401',
    @DateTo smalldatetime = '20180101';


SELECT * FROM @DataSource WHEre date between @DateFrom AND @DateTo
UNION ALL 
SELECT id, max(date) date FROM @DataSource where date < @DateFrom group by id

感谢@gotqn给予帮助的时间