Хранить динамический c список изображений в 1 строке - PullRequest
0 голосов
/ 23 апреля 2020

Я объединяю эти две таблицы и хотел бы отправить представление Test с его изображениями.

  • Тест

    • Имя (VARCHAR (255))
    • TestId (INT)
    • StartTime (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

Что я не нравится здесь, что у меня есть несколько строк из одного теста, но с разными изображениями. Есть ли удобный способ вернуть только одну строку каждого теста с его изображениями?

Мои изображения не такие тяжелые (максимум 100 КБ), и у меня не так много изображений за тест (максимум 10). Вот что я думаю:

  1. Это может звучать странно, но, возможно, на сервере SQL есть способ преобразовать Image в список изображений как VARBINARY(MAX)
  2. Я мог бы иметь 10 столбцов (image1, image2 ...) в виде и заполнить их изображениями, если они существуют (НЕ NULL)

Я немного застрял с этими решениями, так как я Не знаю много о SQL, но я все еще пытаюсь. Вы видите другой способ сделать это? Если нет, не могли бы вы помочь мне с полезными советами о том, как достичь 1. или 2.

Ответы [ 2 ]

2 голосов
/ 23 апреля 2020

Что мне здесь не нравится, так это то, что у меня есть несколько строк из одного теста, но с разными изображениями.

И что? Это всего несколько байтов, повторяемых для каждой строки, что несущественно по сравнению с BLB-объектом размером 100 КБ.

Но вы можете получить данные в нужной форме, если у вас есть 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="
            }
        ]
    }
]
1 голос
/ 23 апреля 2020

Второй вариант можно реализовать с помощью 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
...