объединить два столбца в одну строку столбца, но не одну ячейку и классифицировать их - PullRequest
0 голосов
/ 24 сентября 2019

У меня есть две таблицы: «Таблица A» для уровней («Администратор», «Модератор», «Агент» и т. Д.) И «Таблица В» для пользователей со столбцом, в котором указывается идентификатор уровня со ссылкой на «Таблица А».Я хочу, чтобы хранимая процедура классифицировала имена пользователей по уровням, но результат должен быть в одном столбце только так:

Это две мои таблицы:

TableA
+---------------------------+
|Level ID     |Level Name   |
+---------------------------+
|1            |Admin        |
+---------------------------+
|2            |Moderator    |
+---------------------------+
|3            |Agent        |
+---------------------------+
TableB
+---------------------------+
|Username     |Level ID     |
+---------------------------+
|John         |1            |
+---------------------------+
|Sam          |2            |
+---------------------------+
|Tommy        |2            |
+---------------------------+
|Tony         |3            |
+---------------------------+
|Patrick      |3            |
+---------------------------+
|Jimmy        |3            |
+---------------------------+
|Tod          |3            |
+---------------------------+

Вот какЯ хочу получить результат запроса:

+-------------+
|Admin        |
+-------------+
|  John       |
+-------------+
|             |
+-------------+
|Moderator    |
+-------------+
|  Sam        |
+-------------+
|  Tommy      |
+-------------+
|             |
+-------------+
|Agent        |
+-------------+
|  Tony       |
+-------------+
|  Patrick    |
+-------------+
|  Jimmy      |
+-------------+
|  Tod        |
+-------------+

Это должен быть только один столбец и пробелы перед именами могут быть добавлены с помощью

CONCAT(' ', TableA.Username)

После фамилии есть пустая ячейкакатегория каждого уровня.Я использую SQL Management Studio 18

Ответы [ 3 ]

5 голосов
/ 24 сентября 2019

Используйте union all и order by:

select name
from ((select levelname as name, levelid, 1 as ord
       from tablea
      ) union all
      (select '  ' + username, levelid, 2 as ord
       from tableb
      )
     ) ul
order by levelid, ord;

Это на самом деле не включает пустые строки, которые вы также можете включить:

select name
from ((select levelname as name, levelid, 1 as ord
       from tablea
      ) union all
      (select '  ' + username, levelid, 2 as ord
       from tableb
      ) union all
      (select null, levelid, 0 as ord
       from tablea
       where levelid > 1
      )
     ) ul
order by levelid, ord;

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

0 голосов
/ 24 сентября 2019

Это "пахнет" введением логики "просмотр / вывод" в базу данных ... если у вас есть уровни и имена пользователей через LEFT JOIN, то итерируйте результаты в любом приложении, которое вы создаете, создавая выводкак вам нужно .....

Однако, вот один из способов достижения того, что вы хотите .... все равно не рекомендую, хотя

- редактировать - это движетданные отличаются от ответа @ikram тем, что вам не нужно редактировать сохраненный процесс при добавлении новых уровней

USE tempdb
GO
DROP TABLE IF EXISTS TableA
DROP TABLE IF EXISTS TableB
DROP TABLE IF EXISTS #wibble
GO

CREATE TABLE TableA (
    levelid INTEGER
    , name VARCHAR(10)
)
INSERT INTO TableA
VALUES (1, 'Admin')
    , (2, 'Moderator')
    , (3, 'Agent')

-- SELECT * FROM TableA

CREATE TABLE TableB (
    username VARCHAR(10)
    , levelid INTEGER
)

INSERT INTO TableB
VALUES ('John', 1)
    , ('Sam', 2)
    , ('Tommy', 2)
    , ('Tony', 3)
    , ('Patrick', 3)
    , ('Jimmy', 3)

-- SELECT * FROM TableB


-- table to hold interim results before output
CREATE TABLE #wibble (
    wobble varchar(10)
    , dummyorder integer
)

-- first insert, the levels
INSERT INTO #wibble
SELECT name
    , levelid * 1000 -- pick a number where the gap between numbers of users in levels is sufficient -- could be derived via count
FROM TableA

-- second insert, the users, placed "inside" the relevent level
; WITH users AS (
    SELECT '---' + username as username
        , levelid
        , ROW_NUMBER() over (PARTITION by levelid order by username) as rn --row number of that user in that level
    FROM TableB
)
INSERT INTO #wibble
SELECT username, (levelid * 1000) + rn from users
UNION ALL
SELECT null, (levelid * 1000) + rn + 1
FROM ( -- add a "dummy" row into each level, one number up from the max number of users in that level
    SELECT levelid, max(rn) as rn from users
    GROUP BY levelid
) AS D

-- final output
select wobble from #wibble order by dummyorder
0 голосов
/ 24 сентября 2019

Лучшим способом было бы получить записи из базы данных и делать все, что вы хотите на стороне кода (если есть).

Но если вы хотите это в хранимой процедуре, а записи в 'TableA' часто изменяются(Я так не думаю) тогда вам нужно использовать loop .Я бы не рекомендовал это, потому что циклы в запросах влияют на время выполнения запроса .

. Поэтому я хотел бы поделиться решением с жестко закодированным 'LevelNames' в запросе:

CREATE PROCEDURE sp_GetDataInOneColumn

AS
BEGIN
    SELECT 'Admin'
    UNION ALL
    SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 1
    UNION ALL
    SELECT ''
    UNION ALL
    SELECT 'Moderator'
    UNION ALL
    SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 2
    UNION ALL
    SELECT ''
    UNION ALL
    SELECT 'Agent'
    UNION ALL
    SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = 3
END

Вот хранимая процедура sql с циклом :

CREATE PROCEDURE sp_GetDataInOneColumnWithLoop

AS
BEGIN

    CREATE TABLE #DataInOneColumn (
        Names VARCHAR(MAX)
    );

    SELECT *
    INTO   #Temp
    FROM   TableA

    DECLARE @LevelId int
    DECLARE @LevelName nvarchar(100)    

    WHILE EXISTS(SELECT * FROM #Temp)
    BEGIN

        SELECT TOP 1 @LevelId = [Level ID], @LevelName = [Level Name] From #Temp ORDER BY [Level ID]

        IF (EXISTS(SELECT * FROM TableB WHERE [Level ID] = @LevelId))
        BEGIN       
            INSERT INTO #DataInOneColumn VALUES('')
            INSERT INTO #DataInOneColumn VALUES(@LevelName)
            INSERT INTO #DataInOneColumn SELECT CONCAT(' ', Username) FROM TableB WHERE [Level ID] = @LevelId
        END
        DELETE #Temp WHERE [Level ID] = @LevelId

    END

    SELECT Names FROM #DataInOneColumn
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...