SQL оставил соединение с несколькими строками в одной строке - PullRequest
2 голосов
/ 01 апреля 2010

По сути, у меня есть две таблицы, таблица А содержит фактические элементы, которые мне нужны, а таблица В используется для языковых переводов.

Так, например, таблица А содержит фактическое содержание. В любое время, когда текст используется в таблице, вместо хранения фактических значений varchar сохраняются идентификаторы, которые относятся к тексту, хранящемуся в таблице B. Это позволяет мне, добавив столбец languageID в таблицу B, иметь несколько переводов для одной и той же строки в базы данных.

Пример:

Таблица A

  • Заголовок (int)
  • Описание (int)
  • Другие данные ....

Таблица B

  • TextID (int) - это столбец чье значение хранится в других таблицах
  • LanguageID (int)
  • Текст (varchar)

Мой вопрос - это скорее призыв к предложениям о том, как лучше всего справиться с этим. В идеале я хочу запрос, который я могу использовать, чтобы выбрать из таблицы, и получить текст в отличие от идентификаторов текста из таблицы. В настоящее время, когда у меня есть два текстовых элемента в таблице, это то, что я делаю:

SELECT C.ID, C.Title, D.Text AS Description
FROM
(SELECT A.ID, A.Description, B.Text AS Title
FROM TableA A, TranslationsTable B
WHERE A.Title = B.TextID AND B.LanguaugeID = 1) C
LEFT JOIN TranslationsTable D
ON C.Description = D.TextID AND D.LanguaugeID = 1

Этот запрос дает мне строку из таблицы A, которую я ищу (используя операторы where во внутреннем операторе select) с фактическим текстом на основе идентификатора языка, используемого вместо текстовых идентификаторов.

Это прекрасно работает, когда я использую только один или два текстовых элемента, которые необходимо перевести, но при добавлении третьего или более элементов он становится очень запутанным - по сути, еще одно левое соединение поверх примера.

Есть предложения по улучшению запроса или хотя бы хороший способ обработки 3 или более текстовых элементов в одной строке?

В соответствии с предложениями я добавил пример двух таблиц:

    Table A  
    ---------------------------
    ID    |Title    |Description  
    ---------------------------  
    1     |1        |2  
    ---------------------------  
    2     |3        |4  
    --------------------------- 

    Table B (Translations Table) 
    ---------------------------
    ID    |LanguaugeID|Text  
    ---------------------------  
    1     |1        |Here is title one
    ---------------------------  
    1     |2        |Here is a title one in espanol
    ---------------------------
    2     |1        |Here is description one
    ---------------------------  
    2     |2        |Here is description one in espanol
    ---------------------------
    3     |1        |Title 2
    ---------------------------  
    4     |1        |Description 2
    ---------------------------   

Мне нужно иметь возможность извлечь строку из таблицы A, в которой уже есть текст из таблицы B, а не только идентификаторы, и сделать это для нескольких столбцов, для которых требуется перевод.

Ответы [ 5 ]

1 голос
/ 01 апреля 2010

Изучите использование функции для возврата данных для каждого столбца, который требует перевода. Можно было бы:

CREATE FUNCTION dbo.fTranslate
    (@TextId int, @LanguageId int)
RETURNS nvarchar(100)  --  Should use nvarchar, and set to max length of string
AS
 BEGIN
    SELECT [Text]  --  Reserved wordin SQL, rename that column!
     FROM TableB
     WHERE TextId = @TextId
      And LanguageId = @LanguageId
 END

Затем напишите запрос как:

SELECT
  ID,
  dbo.fTranslate(Title, @LanguageId) Title,
  dbo.fTranslate(Description, @LanguageId) Description
 FROM TableA

Это может работать не очень хорошо, так как вам нужно вызывать функцию один раз для каждого переведенного столбца для каждой возвращаемой строки (т.е. 3 столбца для 100 строк = 300 вызовов функции), но если вы возвращаете только одну строку в время, возможно, не так плохо. Проверь это и будь осторожен.

1 голос
/ 01 апреля 2010

Значит, TableA - это в основном таблица со всеми внешними ключами для TableB? Вы можете создать представление, включающее все объединения в TableB. В нем могут быть столбцы для идентификатора, LanguageID, TitleText, DescriptionText и т. Д. В представлении будет по одной строке для каждого языка, чтобы можно было выбрать язык для конкретной строки, ограничив LanguageID.

1 голос
/ 01 апреля 2010

Звучит так, будто вы хотите получить выгоду от преобразования некоторых данных строки в данные столбца. В этом случае посмотрите функциональность PIVOT здесь

http://msdn.microsoft.com/en-us/library/ms177410.aspx

Вы можете написать запрос в PIVOT из текста, чтобы получить следующий вывод

ID, Title, Description, LanguageId, Text1, Text2, Text3, Text4

Единственный недостаток PIVOT в TSQL заключается в том, что вам нужно заранее определить количество столбцов Pivot (при написании запроса). Однако вы можете преодолеть это, написав динамический SQL.

0 голосов
/ 09 марта 2012

Я думаю, что вид здесь более уместен, как сказал Джейми Ид .В следующем примере вы можете создать LocalisedMessages и LocalisedArticles из второго запроса как представления.

-- i18n.sql (TransactSQL)

create table #Languages(ID int, Code char(2), LanguageName varchar(32));
create table #_Messages(ID int, DefaultText nvarchar(1024));
create table #Translations(ID int, MessageID int, LanguageID int, TranslatedText nvarchar(1024));
create table #Articles(ID int, TitleID int, ContentID int);


insert into #Languages(ID, Code, LanguageName) values
    ( 1, 'en', 'English'  ),
    ( 2, 'es', 'Espagnol' );

insert into #_Messages(ID, DefaultText) values
    ( 1, 'Title 1'   ),
    ( 2, 'Content 1' ),
    ( 3, 'Title 2'   ),
    ( 4, 'Content 2' );

insert into #Translations
    ( ID, MessageID, LanguageID,  TranslatedText ) values
    (  1,         1,          1,  'Title 1'      ),
    (  2,         2,          1,  'Content 1'    ),
    (  3,         1,          2,  'Título 1'     ),
    (  4,         2,          2,  'Contenido 1'  ),
    (  5,         3,          1,  'Title 2'      ),
    (  6,         4,          1,  'Content 2'    ),
    (  7,         3,          2,  'Título 2'     ),
    (  8,         4,          2,  'Contenido 2'  );

insert into #Articles(ID, TitleID, ContentID) values
    ( 1, 1, 2 ),
    ( 2, 3, 4 );


select _m.ID, _m.DefaultText, _t.TranslatedText, _l.ID as LanguageID, _l.Code as LanguageCode
    from #_Messages _m
        inner join #Translations _t on _t.MessageID = _m.ID
        inner join #Languages _l on _l.ID = _t.LanguageID;


with LocalisedMessages as (
    select _m.ID, _m.DefaultText, _t.TranslatedText, _l.ID as LanguageID, _l.Code as LanguageCode
        from #_Messages _m
            inner join #Translations _t on _t.MessageID = _m.ID
            inner join #Languages _l on _l.ID = _t.LanguageID
    ),
LocalisedArticles as (
    select _a.ID, _l.Code as LanguageCode
        , isnull(_mt.TranslatedText, _mt.DefaultText) as Title
        , isnull(_mc.TranslatedText, _mc.DefaultText) as Content
        from #Articles _a
            inner join LocalisedMessages _mt on _mt.ID = _a.TitleID
            inner join LocalisedMessages _mc on _mc.ID = _a.ContentID
            inner join #Languages _l on _l.ID = _mt.LanguageID and _l.ID = _mc.LanguageID
    )
    select *
        from LocalisedArticles;


drop table #Articles;
drop table #Translations;
drop table #_Messages;
drop table #Languages;
0 голосов
/ 09 марта 2012

Я делаю это с UNION, например, 3 различных SELECT STATEMENTS (по одному для каждого языка), где вы предоставляете пустые столбцы для языка, на котором вы не работаете, что-то вроде

SELECT A.ITM_ID, A.ITM_LOOKUPNAME, B.ITM_DESC_TEXT as TitleFR, B.ITM_DESC_UNIT AS UnitFR,'' as TitleEN, '' as UnitEN
FROM Item A, Item_description B
WHERE A.ITM_ID = B.ITM_ID AND B.ITM_DESC_LANG = 1

UNION

SELECT A.ITM_ID, A.ITM_LOOKUPNAME, '' as TitleFR, '' as UnitFR, B.ITM_DESC_TEXT as TitleEN, B.ITM_DESC_UNIT AS UnitEN
FROM Item A, Item_description B
WHERE A.ITM_ID = B.ITM_ID AND B.ITM_DESC_LANG = 2

Затем вы можете сделать выбор с групповой функцией на полученном наборе.

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