2009-02-19 2 views
3

У меня есть данные в таблице MSSQL (TableB) где [DBO] .tableB.myColumn меняет формат после определенной даты ...Динамический/условный SQL-соединение?

Я делаю простой Присоединяйтесь к этой таблице ..

Select [dbo].tableB.theColumnINeed from [dbo].tableA 
left outer join [dbo].tableB on [dbo].tableA.myColumn = [dbo].tableB.myColumn 

Однако мне нужно присоединиться, используя другое форматирование, на основе столбца даты в таблице A ([dbo] .tableA.myDateColumn).

Что-то вроде ...

Select [dbo].tableB.theColumnINeed from [dbo].tableA 
left outer join [dbo].tableB on [dbo].tableA.myColumn = 
    IF [dbo].tableA.myDateColumn > '1/1/2009' 
     BEGIN 
      FormatColumnOneWay([dbo].tableB.myColumn) 
     END 
    ELSE 
     BEGIN 
      FormatColumnAnotherWay([dbo].tableB.myColumn) 
     END 

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

ответ

8
SELECT [dbo].tableB.theColumnINeed 
FROM [dbo].tableA 
LEFT OUTER JOIN [dbo].tableB 
ON [dbo].tableA.myColumn = 
    CASE 
    WHEN [dbo].tableA.myDateColumn <= '1/1/2009' THEN FormatColumnOneWay([dbo].tableB.myColumn) 
    ELSE FormatColumnAnotherWay([dbo].tableB.myColumn) 
    END 
0

С [dbo] префикс, я считаю, что вы используете SQL Server. Хотя у меня нет большого опыта работы с ним, вы можете преобразовать оба поля в определенный формат даты:

select * from tableA 
    Left Outer join tableB 
     On CONVERT(CHAR(8), tableA.myColumn, 112) = CONVERT(CHAR(8), tableB.myColumn, 112) 

То же самое должно работать на любой СУБД, используя соответствующие функции форматирования даты.

Я не знаю о SQL Server, но в Oracle вы можете создать индекс для выражения объединения.

0

В SQL Server вы хотите использовать СЛУЧАЙ, такие как:

SELECT * 
FROM TableA 
INNER JOIN TableB on TableA.Column= 
CASE WHEN TableA.RecordDate>'1/2/08' 
     THEN FormatCoumn(TableB.Column) 
    ELSE FormatColumnOtherWat(TableB.Column) 
END 
+0

Мое предложение было бы исправить данные, потому что оптимизатор будет игнорировать индексы с этими функциями в состоянии JOIN – SQLMenace

+0

Да, но иногда вы не можете исправить данные ;-) – JoshBerke

+0

Это тот же столбец, я бы его исправить, поместил на него ПРОВЕРИТЬ КОНСТРУИРОВАТЬ, чтобы это не повторилось, потому что рано или поздно кто-то закричит, что производительность неприемлема, а потом что? – SQLMenace

0

Вы знаете, что это плохо для производительности, так как вы не сможете использовать индексы правильные?

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

0

Ну, вы могли бы использовать подзапрос правильно отформатировать данные в таблице перед соединением.

SELECT 
    newB.columnINeed 
FROM 
    tableA AS A 
LEFT OUTER JOIN (
    SELECT 
    columnINeed 
    , CASE WHEN myColumn > '1/1/2009' THEN FormatColumnOneWay(myColumn) 
    ELSE FormatColumnAnotherWay(myColumn) 
    END AS myColumn 
    FROM 
    tableB 
) AS NewB ON A.myColumn = B.myColumn 

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

+0

Возможно, вы не сможете это сделать. Я замечаю, что вы форматируете B на основе A. Мое предположение: вы, вероятно, можете отформатировать B без привлечения A, а затем присоединиться? – alphadogg

0

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

«Правильная» вещь, действительно, состоит в том, чтобы повторить ее и сделать это правильно, чтобы начать. Ваши даты должны храниться в столбцах datetime, и вам, вероятно, потребуется немало усилий для переноса всех ваших дат в таблицеB в столбец datetime. Вы можете сделать это таким образом, среди прочего:

  1. Добавить столбец dummie в TableB с типом datetime.
  2. Запустить запрос, который принимает значение даты из текущего столбца и помещает его в столбец datetime.
  3. Переименовать и удалить столбцы в соответствии с предыдущей структурой данных.
+0

Вы забыли Шаг 4: Проведите недели или месяцы, чтобы устранить все ошибки, вызванные другими кодами/отчетами об удалении столбца – CodeRedick

+0

Сделайте это в представлении. Почему люди больше не используют представления? Прямой доступ к таблице является злом ... – alphadogg

+0

Ну, значения datetime, не сохраненные в столбцах datetime, также являются злыми. В зависимости от того, насколько велико приложение, использующее базу данных, может быть много проблем - да, но если вы использовали хорошее разделение проблем и т. Д., У вас не будет много мест для изменения. Зачем тратить время на вонючий код? –

0

Хорошо, держите. Каков фактический тип данных столбца? Я предполагаю, что это не DateTime, потому что вы не контролируете форматирование ...он просто сохраняет дату. Может ли это быть CAST или CONVERTED для DateTime?

Таким образом, вы можете

left outer join tableb on tableA.myColumn = CAST(tableb.MyColumn as DateTime) 

Таким образом, вы не совпадая строку, но фактическая дата, которая должна быть более надежным. Это также проще и легче читать. Реальные вопросы - почему дата не хранится как DateTime в hte первое место ...

5

Вместо того, чтобы иметь оператор CASE в JOIN, который предотвратит запрос с использованием индексов, вы можете рассмотреть возможность использования UNION

SELECT [dbo].tableB.theColumnINeed 
FROM [dbo].tableA 
    LEFT OUTER JOIN [dbo].tableB 
     ON [dbo].tableA.myDateColumn > '1/1/2009' 
     AND [dbo].tableA.myColumn = FormatColumnOneWay([dbo].tableB.myColumn) 
UNION ALL 
SELECT [dbo].tableB.theColumnINeed 
FROM [dbo].tableA 
    LEFT OUTER JOIN [dbo].tableB 
     ON [dbo].tableA.myDateColumn <= '1/1/2009' 
     AND [dbo].tableA.myColumn = FormatColumnAnotherWay([dbo].tableB.myColumn) 

но если FormatColumnOneWay/FormatColumnAnotherWay являются функции или поля выражения, которые, вероятно, будет исключить использование inxdexes на [MyColumn], хотя любой индекс по myDateColumn прежнему следует использовать

Однако, это могло бы помогите понять, что такое логика FormatColumnOneWay/FormatColumnAnotherWay, как известно, что может позволить лучшей оптимизации

Пара вещей, чтобы отметить:

UNION ALL не удалит дубликаты (в отличие от UNION). Поскольку два подзапроса являются взаимоисключающими, это нормально и сохраняет шаг SORT, который UNION сделает, чтобы позволить ему удалять дубликаты.

Вы не должны использовать стиль «1/1/2009» для строковых дат, вы должны использовать стиль «yyyymmdd» без и слэши или дефисы (вы также можете использовать CONVERT с параметром, чтобы явно указывать, что строка находится в d/m/y или m/d/y style

+0

хорошая обратная связь .. спасибо. – madcolor