根据多个(复杂)条件选择数据

时间:2021-02-01 20:54:42

标签: sql sql-server tsql

我的服务器上有这种数据结构:

文件表:

+----------+--------+------------+
| SystemId | FileId | FileTypeId |
+----------+--------+------------+
|        1 |    100 |          2 |
|        2 |    101 |          1 |
|        2 |    102 |          2 |
|        2 |    103 |          3 |
|        3 |    104 |          1 |
+----------+--------+------------+

文件历史表:

+--------+------------+------------------+
| FileId | FileStatus | StatusChangeDate |
+--------+------------+------------------+
|    101 | Done       | 29.01.2021       |
|    101 | Reverted   | 06.01.2021       |
|    101 | Done       | 05.01.2021       |
|    101 | InProgress | 04.01.2021       |
|    101 | New        | 04.01.2021       |
|    102 | Done       | 20.05.2020       |
|    102 | InProgress | 20.05.2020       |
|    102 | New        | 19.05.2019       |
|    103 | New        | 15.04.2019       |
+--------+------------+------------------+

链接文件表

+--------+----------------+------------------+
| FileId | LinkedFileName |    LinkToFile    |
+--------+----------------+------------------+
|    101 | LinkedFile1    | www.file.com/123 |
|    101 | LinkedFile2    | www.file.com/124 |
|    101 | LinkedFile3    | www.file.com/125 |
|    104 | LinkedFile4    | www.file.com/126 |
+--------+----------------+------------------+

我需要提取的是 SystemId 以及存在这样一个 SystemId 的 LinkedFileName 和 LinkToFile,其中包含一个或多个 FileTypeId = 1 的文件以及一个或多个 FileTypeId = 2 的文件,它们都处于状态“完成”并且这些文件中的任何一个在上周内都有 StatusChangeDate。我想出了这样的东西,但它并不完全是我需要的,而且速度非常慢。

SELECT s.SystemId, s.SystemName, files.FileId, linkedfiles.LinkedFileName, linkedfiles.LinkToFile
FROM SystemsTable s
CROSS APPLY (
    SELECT f.FileId as FileId
    FROM FilesTable f
    WHERE s.SystemId = f.SystemId
    AND f.FileTypeId = 1
    AND EXISTS (
        SELECT TOP 1 fh.*
        FROM FileHistoryTable fh
        WHERE fh.FileId = f.FileId
        AND fh.FileStatus = 'Done' 
        AND fh.StatusChangeDate  >= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 0) 
        AND fh.StatusChangeDate  <= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 6)
        ORDER BY fh.StatusChangeDate  DESC 
        )
    ) files
CROSS APPLY (
    SELECT lf.LinkedFileName as LinkedFileName, lf.LinkToFile as LinkToFile
    FROM LinkedFiles lf
    WHERE lf.FileId = files.FileId
) linkedfiles
WHERE EXISTS (
    SELECT f.FileId as FileId
    FROM FilesTable f
    WHERE s.SystemId = f.SystemId
    AND f.FileTypeId = 2
    AND EXISTS (
        SELECT TOP 1 fh.*
        FROM FileHistoryTable fh
        WHERE fh.FileId = f.FileId
        AND fh.FileStatus = 'Done' 
        AND fh.StatusChangeDate  >= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 0) 
        AND fh.StatusChangeDate  <= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 6)
        ORDER BY fh.StatusChangeDate  DESC 
        )
)

其他评论:

  • 只有 FileTypeId = 1 可以包含链接文件
  • 上表的预期结果是:
+----------+------------+--------+----------------+------------------+
| SystemId | SystemName | FileId | LinkedFileName |    LinkToFile    |
+----------+------------+--------+----------------+------------------+
|        2 | System2    |    101 | LinkedFile1    | www.file.com/123 |
|        2 | System2    |    101 | LinkedFile2    | www.file.com/124 |
|        2 | System2    |    101 | LinkedFile3    | www.file.com/125 |
+----------+------------+--------+----------------+------------------+

3 个答案:

答案 0 :(得分:0)

我相信这对你有用:

import android.app.Activity;
import android.graphics.*;
import android.graphics.drawable.*;

public class TextDrawable extends Drawable {

    private final Bitmap icon;
    private final String text;
    private final Paint paint;

    public TextDrawable(Activity activity, String text) {

        this.text = text;

        // load image to show alongside the text
        icon = BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_shopping_cart);

        this.paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setTextSize(42f); // make much bigger -- I'm just using a number for my text
        paint.setAntiAlias(true);
        paint.setFakeBoldText(true);
        paint.setShadowLayer(6f, 0, 0, Color.BLACK);
        paint.setStyle(Paint.Style.FILL);
        paint.setTextAlign(Paint.Align.LEFT);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawBitmap(icon, -15, 0, paint); // icon offset slightly to the left
        canvas.drawText(text, 35, 40, paint); // offset to have number to the right of the icon
    }

    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        paint.setColorFilter(cf);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

答案 1 :(得分:0)

这是至少返回您需要的查询。

关于性能。 最重要的部分是获取文件的最新版本。为此,您需要按 FileHistory 和其他一些条件对 StatusChangeDate 行进行排序以处理关系。或者改用 datetime 列。因此,您可以使用 row_number() 函数或通过 apply 使用 select top 1 ... order by StatusChangeDate desc 进行索引查找,具体取决于有多少类型 1 和 2 的文件。如果大约是 80%,那么 row_number 看起来更可取。或者,如果您有此数据的单个编写者,则可以在插入时管理一些 last_version 标志(对于单个编写者,查找当前最新版本不应该存在并发问题)并对其进行索引以摆脱这种计算.

db<>fiddle here.

  select systemid
  from file_ as f
    cross apply (
      /*The last state*/
      select top 1 *
      from filehistory as fh
      where fh.fileid = f.fileid
      order by
        StatusChangeDate desc
        /*In case there was multiple changes in the same day
          you need to use datetime column type and index on (fileid, StatusChangeDate desc).
          
          Or define the priority of statuses as computed column, index this column also
          and order by it in the same direction as in index
        */
        /*case
          when filestatus = 'Done'
          then 1
          else 0
        end desc*/
    ) as cfv
  where 1 = 1
    /*It is Done at the end*/
    and cfv.filestatus = 'Done'
    and f.filetypeid in (1, 2)
  group by systemid
  /*Where there's at least one file of type 1 and at least one of type 2*/
  having sum(case f.filetypeid when 1 then 1 end) >= 1
    and sum(case f.filetypeid when 2 then 1 end) >= 1
    /*And the change was within previous week*/
    and sum(case
      when StatusChangeDate
          between DATEADD(dd, -(DATEPART(dw, getdate())-1) - 7, getdate())
          and DATEADD(dd, -(DATEPART(dw, getdate())), getdate())
      then 1
      end
    ) >= 1
)
select
  f.systemid,
  f.fileid,
  lf.linkedfilename,
  lf.LinkToFile
from file_ as f
  join selected_systems as ss
    on f.systemid = ss.systemid
  join linkedfile as lf
    on f.fileid = lf.fileid

答案 2 :(得分:0)

你可以试试这样的

with
id_cte(SystemId, FileId, FileTypeId) as (
    select f.*
    from FilesTable f
         cross apply (select top(1) FileStatus 
                      from FileHistoryTable fh
                      where fh.FileId = f.FileId
                            and fh.StatusChangeDate  >= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 0) 
                            and fh.StatusChangeDate  <= DATEADD(wk, DATEDIFF(wk, 7, GETDATE()), 6)
                      order by fh.StatusChangeDate  desc) fs
    where f.FileTypeId in(1, 2)
          and fs.FileStatus='Done')
SELECT f.SystemId, f.FileId, lf.LinkedFileName, lf.LinkToFile
FROM id_cte sc
      join FilesTable f on sc.SystemId=f.SystemId
                           and sc.FileId=f.FileId
     join LinkedFiles lf on f.FileId=lf.FileId;
SystemId    FileId  LinkedFileName  LinkToFile
2           101     LinkedFile1     www.file.com/123
2           101     LinkedFile2     www.file.com/124
2           101     LinkedFile3     www.file.com/125

fiddle

相关问题