Свести реляционные данные для сводки / экспорта - PullRequest
1 голос
/ 14 апреля 2009

Скажем, у нас есть две таблицы в базе данных MS Access:

Сервисные пользователи:

| ID | Name | Other details... |
| 1  | Joe  | Blah...          |
| 2  | Fred | Qwerty...        |
| 3  | Bob  | Something else...|

Команды, предоставляющие услуги:

| ID | TeamID | UserID |
| 1  | T1     | 1      |
| 2  | T2     | 1      |
| 3  | T2     | 2      |
| 4  | T3     | 2      |
| 5  | T3     | 3      |

Мне нужно создать сводный запрос, который создает по одной строке для каждого пользователя, причем первые несколько команд (по TeamID) назначаются в отдельных столбцах. Как:

Запрос:

| UserID | Name | Team1 | Team2 |
| 1      | Joe  | T1    | T2    |
| 2      | Fred | T2    | T3    |
| 3      | Bob  | T3    | Null  |

Я могу получить столбец Team1 с помощью max () из запроса на дополнительный выбор, но у меня полный ментальный блок на пути достижения Team2, Team3 и т. Д. (Да, я знаю, что если будет назначено больше команд для пользователя, чем я создаю столбцы, запрос потеряет эту информацию: это не проблема).

Редактировать: чтобы уточнить, количество столбцов в запросе будет фиксированным (в реальном запросе всегда будет 7). Если команд меньше, чем столбцов, дополнительные столбцы должны быть пустыми (как в примере). Если команд больше, чем столбцов, в этой сводке будут показаны только первые 7 команд.

Редактировать 2 - Возможное решение, которое не работает ...:

Я пытался ...

SELECT UserTable.ID As UID, UserTable.Name, 
(SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID
ORDER BY TeamID) As Team1
FROM UserTable

... который отлично работает. К сожалению ...

SELECT UserTable.ID As UID, UserTable.Name, 
(SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID
ORDER BY TeamID) As Team1,
(SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID
AND TeamID <> Team1 ORDER BY TeamID) As Team2
FROM UserTable

... выдает окно параметров для Team1. Идеи о том, как пропустить первые / вторые / и т. Д. Значения из реактивного запроса?

Ответы [ 4 ]

2 голосов
/ 14 апреля 2009

Подходит кросс-таблица.

Запрос 1: называется TeamUser

SELECT Teams.UserID, ServiceUsers.SName, Teams.TeamID
FROM ServiceUsers 
INNER JOIN Teams ON ServiceUsers.ID = Teams.UserID;

Перекрестный

TRANSFORM First(TeamUser.TeamID) AS FirstOfTeamID
SELECT TeamUser.UserID, TeamUser.SName
FROM TeamUser
GROUP BY TeamUser.UserID, TeamUser.SName
PIVOT TeamUser.TeamID;

РЕДАКТИРОВАТЬ в ответ на комментарии

Должна быть возможность объединить два запроса и использовать объединенный запрос, чтобы уменьшить количество записей.

TRANSFORM First(t.ATeamID) AS FirstOfATeamID
SELECT t.UserID, s.SName
FROM (SELECT Teams.UserID, First(Teams.ID) AS FirstOfID, 
             First(Teams.TeamID) AS ATeamID, "1st" As TeamCount
      FROM Teams
      GROUP BY Teams.UserID
      UNION 
      SELECT Teams.UserID, First(Teams.ID) AS FirstOfID, 
             First(Teams.TeamID) AS ATeamID, "2nd" As TeamCount
      FROM Teams
      WHERE ID Not In (SELECT First(Teams.ID) 
                       FROM Teams GROUP BY Teams.UserID)
      GROUP BY Teams.UserID) t
INNER JOIN ServiceUsers s ON t.UserID = s.ID
GROUP BY t.UserID, s.SName
PIVOT t.TeamCount
2 голосов
/ 14 апреля 2009

Во-первых, вам нужен запрос, чтобы назначить число от 1 до N командам, связанным с пользователем:

SELECT UserID, TeamID, 
       (SELECT count(*) FROM TeamTable t2 WHERE t2.TeamID <= TeamTable.TeamID and t2.UserID=TeamTable.UserID) AS position 
FROM TeamTable 
ORDER BY TeamID

Давайте назовем этот запрос TeamList. Теперь вы можете использовать этот запрос в основном запросе, вызывая его 7 раз, каждый раз фильтруя другую позицию:

SELECT UserTable.ID As UID, UserTable.Name, 
   (SELECT TeamID FROM TeamList WHERE UserTable.ID = TeamList.UserID AND position=1) As Team1,
   (SELECT TeamID FROM TeamList WHERE UserTable.ID = TeamList.UserID AND position=2) As Team2,
   [...]
FROM UserTable 

Вы можете собрать все это в одном запросе, но более практично определить запрос TeamList и вызывать его несколько раз. Также обратите внимание, что этот способ нумерации основан на порядке TeamID. Вы можете выбрать другой порядок, изменив запрос TeamList, но в выбранном вами поле должны быть разные уникальные значения для каждой команды (или сравнение

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

0 голосов
/ 24 мая 2012

Просто поместите Team1 в качестве подзапроса таким образом, как заполняется Team1, прежде чем ссылаться на него при получении Team2

SELECT UserTable.ID As UID,UserTable.Name,T1.Team1,
(SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID AND TeamID <> T1.Team1 ORDER BY TeamID) As Team2 
FROM UserTable 
LEFT OUTER JOIN
    (
        SELECT UserTable.ID As UID,  
           (SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID 
        ORDER BY TeamID) As Team1, 
        FROM UserTable 
    )T1 ON UserTable.ID=T1.UID

Это также будет работать с CTE:

;With CTE_Team1 As (
        SELECT UserTable.ID As UID,  
           (SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID ORDER BY TeamID) As Team1, 
        FROM UserTable )
SELECT UserTable.ID As UID,UserTable.Name,T1.Team1,
   (SELECT TOP 1 TeamID FROM TeamTable WHERE UserTable.ID = TeamTable.UserID AND TeamID <> T1.Team1 ORDER BY TeamID) As Team2 
FROM UserTable 
LEFT OUTER JOIN
CTE_Team1 T1 ON UserTable.ID=T1.UID
0 голосов
/ 14 апреля 2009

Я не эксперт по MS-Access, но нет ли способа пропустить строки в ваших подзапросах? Так, для Team1 вы пропускаете 0 строк, для Team2 вы пропускаете 1 строку и т. Д. Каждый раз, когда вы используете MAX (), чтобы выбрать максимальное значение из строк в вашем подзапросе. Так как каждый раз на одну строку меньше, вы получаете другое максимальное значение каждый раз (если вы, конечно, сортируете свой результат подзапроса).

Общая идея заключается в том, что каждый из ваших подзапросов (для Team1, Team2, ...) возвращает на одно меньшее значение, так что ваша функция MAX () каждый раз возвращает другое значение.

Взглянув на то, что возможно с MS-Access SQL, вы можете использовать только TOP. Но тогда вы должны знать, сколько строк имеет ваш подзапрос. Это невозможно, я думаю. Предположим, что вы это знаете, и пользователь является членом 3 команд, ваш подзапрос на группу включает SELECT TOP(3) ..., SELECT TOP(2) ..., SELECT TOP(1)....

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