【问题标题】:Store a dynamic list of images in 1 row将图像的动态列表存储在 1 行中
【发布时间】:2020-08-06 03:27:46
【问题描述】:

我正在加入这两个表,我想发送Test 的视图及其图像。

  • 测试

    • 名称(VARCHAR(255))
    • TestId (INT)
    • 开始时间 (DATETIME2(7))
    • 状态 (VARCHAR(255))
  • 图片

    • ImageId (INT)
    • TestId (INT)
    • 图像(VARBINARY(MAX))

现在我正在这样做:

SELECT Name, t.TestId, StartTime, Status, Image
FROM [Test] t
LEFT JOIN [Images] i ON i.TestId = t.TestId

我不喜欢这里的是,我有来自同一个测试的多行但有不同的图像。有没有一种方便的方法可以只返回每个测试的一行及其图像?

我的图片不是很重(最大 100KB),而且每次测试我没有很多图片(最大 10 个)。这是我的想法:

  1. 这可能听起来很疯狂,但也许在 SQL Server 中,有一种方法可以将 Images 转换为图像列表作为 VARBINARY(MAX)
  2. 我可以在视图中有 10 列(image1、image2...),如果它们存在,则用图像填充它们(非空)

我对这些解决方案有点坚持,因为我对 SQL 了解不多,但我仍在尝试。你看到另一种方法吗?如果没有,您能否就如何实现 1. 或 2. 提供有用的建议。

【问题讨论】:

    标签: sql-server tsql join group-by varbinarymax


    【解决方案1】:

    我不喜欢这里的是,我有来自同一个测试的多行但有不同的图像。

    那又怎样?每行只重复几个字节,这与 100KB 的 blob 相比微不足道。

    但是,如果您让 SQL Server 将数据转换为 JSON,您可以完全按照您想要的形状检索数据。 varbinary(max) 将被 base64 编码并添加所有 JSON 开销,这将是一个更大的结果大小。但是像

    这样的查询
    SELECT Name , 
           t.TestId , 
           StartTime , 
           Status ,  
           (select Image from Images where testid = t.testid for json path) Images
    FROM [Test] t
    for json path
    

    会输出类似的数据

    [
        {
            "Name": "Test1",
            "TestId": 1,
            "StartTime": "2020-04-22T18:15:47.9533333",
            "Status": "complete",
            "Images": [
                {
                    "Image": "j2LYPy9Uy0Wbz0/qsPk0qo9i2D8vVMtFm89P6rD5NKqPYtg/L1TLRZvPT+qw+TSqj2LYPy9Uy0Wbz0/qsPk0qo9i2D8vVMtFm89P6rD5NKo="
                },
                {
                    "Image": "j2LYPy9Uy0Wbz0/qsPk0qo9i2D8vVMtFm89P6rD5NKqPYtg/L1TLRZvPT+qw+TSqj2LYPy9Uy0Wbz0/qsPk0qo9i2D8vVMtFm89P6rD5NKo="
                }
            ]
        }
    ]
    

    【讨论】:

      【解决方案2】:

      第二个选项可以使用row_number() 和条件聚合来实现,如下所示:

      select 
          t.name,
          t.testid,
          t.starttime,
          t.status,
          max(case when i.rn =  1 then i.image end) image01,
          max(case when i.rn =  2 then i.image end) image02,
          ...
          max(case when i.rn = 10 then i.image end) image10
      from test t
      left join (
          select testid, image, row_number() over(partition by testid order by imageid) rn
          from images
      ) i on i.testid = t.testid
      group by t.name, t.testid, t.starttime, t.status
      

      你也可以使用outer apply,这样可能更高效:

      select
          t.*,
          i.*
      from test t
      outer apply (
          select 
              max(case when rn =  1 then image end) image01,
              max(case when rn =  2 then image end) image02
              ...
              max(case when rn = 10 then image end) image10
          from (
              select image, row_number() over(order by imageid) rn
              from image i
              where i.testid = t.testid
          ) i
      ) i
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-06
        • 2014-08-06
        • 1970-01-01
        • 2010-11-15
        • 1970-01-01
        • 2020-11-07
        • 1970-01-01
        相关资源
        最近更新 更多