在 1 行中存储动态图像列表

Store a dynamic list of images in 1 row

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

现在我正在这样做:

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

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

我的图像没有那么大(最大 100KB)而且每次测试我没有很多图像(最大 10 张)。这是我的想法:

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

我不太了解这些解决方案,因为我对 SQL 了解不多,但我仍在尝试。你看到另一种方法吗?如果没有,您能帮我提供有关如何实现 1. 或 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

What I don't like here is that I have multiple rows from the same test but with different images.

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

但是如果您有 SQL 服务器将其转换为 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="
            }
        ]
    }
]