SQL-запрос - один столбец должен быть отдельным, ограниченный столбец должен быть самым последним - PullRequest
3 голосов
/ 11 февраля 2010

У меня есть таблица CATEGORIES, которая связана с таблицей ITEMS (один ко многим). Каждая таблица элементов может иметь несколько штрих-кодов в таблице BARCODES (один ко многим).

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

Надеюсь, что это имеет смысл - это немного упрощение.

Пример моих таблиц:

CATEGORIES TABLE
ID   NAME        CODE    ACCOUNTING_REFERENCE
1    Beverages   BEV     Stock_Beverages
2    Pies        PIE     Stock_Pies
3    Chips       CHP     Stock_Chips

ITEMS TABLE
ID   CATEGORY_ID  DESCRIPTION                 BASE_COST
1    1            Red Bull (single)           $4.50
2    2            Ponsonby Pie - Mince Cheese $2.99
3    1            Coke Can (single)           $3.50
4    2            Big Ben - Steak Pepper      $1.99

BARCODES TABLE
ID  ITEM_ID  BARCODE   ACTIVE_FROM
1   1        XSD123    2009/10/11
2   2        AXF123    2009/10/12
3   3        XYZ234    2009/10/11
4   1        NEW001    2010/01/05
5   1        NEW002    2010/01/05*
  • Я знаю, что в этом сценарии не имеет смысла вводить два штрих-кода в один и тот же день. Не обращайте внимания, что это выглядит как плохие данные. Этот пример - всего лишь аналогия того, что я на самом деле делаю - в приложении реального мира, которое отражает эту структуру, имеет смысл ввести два «штрихкода» в один и тот же день. Я хотел бы открыто обсудить реальные данные, но я не свободен в этом - извините, если это сбивает с толку.

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

Это все, что я могу сделать.

Я также хочу, чтобы запрос вернул самый последний штрих-код для элемента. В тех случаях, когда в один и тот же день для элемента вводятся два штрих-кода, не очень важно, какой из них я отображаю, хотя было бы неплохо отобразить более высокое из двух (или более) полей BARCODE.ID.

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

Мой желаемый набор результатов будет выглядеть примерно так:

ITEM_ID   DESCRIPTION                  BASE_COST  CATEGORY_NAME CATEGORY_CODE  ACCOUNTING_REFERENCE  BARCODE
1         Red Bull (single)            $4.50      Beverages     BEV            Stock_Beverages       NEW002
2         Ponsonby Pie - Mince Cheese  $2.99      Pies          PIE            Stock_Pies            AXF123
3         Coke Can (single)            $3.50      Beverages     BEV            Stock_Beverages       XYZ234
4         Big Ben - Steak Pepper       $1.99      Pies          PIE            Stock_Pies            <null>

Я не могу понять, как добавить столбец BARCODE в этот набор результатов, учитывая таблицы выше.

На случай, если мне неясно: мне нужно знать, как структурировать SQL-запрос, который даст мне именно такой результат, учитывая данные, которые я представил.

Требуется, чтобы столбец ITEM_ID в моем наборе результатов был отдельным. Я не могу просто ограничить устаревшие записи в памяти, и если я разыграю несколько ITEM_ID, это нарушит отношение PK / FK, используемое в другом месте приложения, которое я исправляю.

Для справки, я посмотрел на сайте что-нибудь, связанное с различными столбцами sql, чтобы ответить на этот вопрос. Я нашел много записей, но, похоже, ни одно из предложенных решений не помогло мне. Возможно, я просто дремучий - уже поздно, и я не могу думать прямо. Извинения, если я пропустил что-то очевидное.

EDIT

Гейб дал хороший ответ ниже, и я понял, что должен был быть яснее.

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

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

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

РЕДАКТИРОВАТЬ (снова)

Ответы Гейба и Саймона работают. Я выбрал Гейба в качестве ответа просто потому, что нашел его утверждение наиболее разборчивым.

Тем не менее, мне также нравится simon , потому что он показывает синтаксис для использования SQL, с которым я не знаком - хорошо видеть незнакомый синтаксис в действии.

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

Спасибо за помощь.

Ответы [ 2 ]

2 голосов
/ 11 февраля 2010

Похоже, вы хотите коррелированный подзапрос. Примерно это:

 select *
from ITEMS
join BARCODES as B on ITEMS.ID = B.ITEM_ID
join CATEGORIES on CATEGORIES.ID = ITEMS.CATEGORY_ID
where B.ACTIVE_FROM =
    (select max(ACTIVE_FROM)
     from BARCODES as B2
     where B2.ITEM_ID = B.ITEM_ID)

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

 select *
from ITEMS
LEFT OUTER join BARCODES as B on ITEMS.ID = B.ITEM_ID
join CATEGORIES on CATEGORIES.ID = ITEMS.CATEGORY_ID
where B.ACTIVE_FROM =
    (select max(ACTIVE_FROM)
     from BARCODES as B2
     where B2.ITEM_ID = B.ITEM_ID)
    AND B.ID =
    (SELECT MAX(ID)
     FROM BARCODES AS B3
     WHERE B3.ITEM_ID = B.ITEM_ID)
    OR ACTIVE_FROM IS NULL
1 голос
/ 11 февраля 2010

Попробуйте что-то вроде этого:

use tempdb
go
if exists (select 1 from sys.objects where name = 'barcodes')
    drop table barcodes
if exists (select 1 from sys.objects where name = 'items')
    drop table items
if exists (select 1 from sys.objects where name = 'categories')
    drop table categories
go
create table categories (
    id int primary key,
    [name] nvarchar(30),
    code char(3),
    accounting_reference nvarchar(30)
)
create table items (
    id int primary key,
    category_id int foreign key references categories (id),
    description nvarchar(50),
    base_cost money
)
create table barcodes (
    id int primary key,
    item_id int foreign key references items (id),
    barcode varchar(10),
    active_from datetime
)
go
insert into categories (id, [name], code, accounting_reference)
select 1, 'Beverages', 'BEV', 'Stock_Beverages' union all
select 2, 'Pies', 'PIE', 'Stock_Pies' union all
select 3, 'Chips', 'CHP', 'Stock_Chips'

insert into items (id, category_id, description, base_cost)
select 1, 1, 'Red Bull (single)', 4.5 union all
select 2, 2, 'Ponsonby Pie - Mince Cheese', 2.99 union all
select 3, 1, 'Coke Can (single)', 3.50 union all
select 4, 2, 'Big Ben - Steak Pepper', 1.99

insert into barcodes (id, item_id, barcode, active_from)
select 1, 1, 'XSD123', '2009/10/11' union all
select 2, 2, 'AXF123', '2009/10/12' union all
select 3, 3, 'XYZ234', '2009/10/11' union all
select 4, 1, 'NEW001', '2010/01/05' union all
select 5, 1, 'NEW002', '2010/01/05'

;with x as (
    select item_id, max(active_from) active_from, max(id) id
    from barcodes
    group by item_id
),
y as (
    select item_id, barcode
    from barcodes
    where exists (select 1 from x where item_id = barcodes.item_id and id = barcodes.id and active_from = barcodes.active_from)
)
select t1.id item_id, t1.description, t1.base_cost, t2.name category_name, t2.code category_code, t2.accounting_reference, t3.barcode
from items t1 left join categories t2 on (t1.category_id = t2.id)
    left join y t3 on (t1.id = t3.item_id)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...