У меня есть данные из двух таблиц. Элемент и местоположение взяты из таблицы A, а описание из таблицы B. Я пытаюсь написать Oracle SQL, где я могу получить те элементы и местоположения, описание которых в блоке 1 отличается от всех других блоков для того же элемента, но покажите мне только строки с Loc 1 и Loc 2.
Я попытался получить полный список, а затем экспортировать его в Excel, а затем найти дубликаты и т. д., но этот список настолько длинный, что экспорт fn не работает, а также копирование и вставка в Excel.
Конечная цель здесь заключается в том, что мне нужно обновить описание Loc 1 тем, что есть в строках Loc 2.
Итак, вот чего я стремлюсь достичь с помощью этого SQL.
Спасибо МТО. Я отредактирую таблицы, как вы предложили, как только научусь это делать. Что касается самого SQL, спасибо за ваш вклад, но есть два замечания. Обе таблицы объединены еще одним столбцом, назовем его «Item_Identifier», общим для них обоих, который равен 1-1, поэтому я присоединил их по этому поводу. Однако когда я запускаю SQL, я получаю ошибку, указывающую на самую последнюю строку кода. ORA-00904: «LOCATION»: неверный идентификатор 00904. 00000 — «%s: неверный идентификатор» *Причина: *Действие:
................COUNT(ОТЛИЧНОЕ описание) OVER (РАЗДЕЛЕНИЕ ПО элементу) AS num_descr FROM ItemTable A соединить ItemDescriptionTable B с A.Item_Identifier = B. Item_Identifier ) WHERE num_descr = 2.. ........
Привет, MTO! Да, у меня это тоже сработало. Конечно, мне пришлось немного подправить код, но да, это сработало. Все три приведенных ниже SQL-кода представляли собой разные подходы, но я заставил работать и ваш. Спасибо за вашу помощь и усилия.
Вы можете использовать условную агрегацию с аналитическими функциями:
SELECT item,
location,
description
FROM (
SELECT item,
location,
description,
COUNT(DISTINCT CASE location WHEN 'Loc 1' THEN description ELSE NULL END) OVER (
PARTITION BY item
) AS num_loc1,
COUNT(DISTINCT CASE location WHEN 'Loc 1' THEN NULL ELSE description END) OVER (
PARTITION BY item
) AS num_other_loc,
COUNT(DISTINCT description) OVER (PARTITION BY item) AS num_descr
FROM a
INNER JOIN b
ON a.item_id = b.item_id
)
WHERE num_descr > 1
AND num_loc1 = 1
AND num_other_loc + num_loc1 = num_descr
AND location IN ('Loc 1', 'Loc 2')
или, в зависимости от того, как вы хотите реализовать логику «где описание в Loc 1 отличается от всех других Locs для того же элемента», вы можете изменить окончательный фильтр на:
WHERE num_descr > 1
AND num_loc1 = 1
AND num_other_loc + num_loc1 = num_descr
AND location IN ('Loc 1', 'Loc 2')
Что для примера данных:
CREATE TABLE a (item_id, item, location) AS
SELECT 1, 'Item A', 'Loc 1' FROM DUAL UNION ALL
SELECT 2, 'Item A', 'Loc 2' FROM DUAL UNION ALL
SELECT 3, 'Item A', 'Loc 3' FROM DUAL UNION ALL
SELECT 4, 'Item A', 'Loc 4' FROM DUAL UNION ALL
SELECT 5, 'Item B', 'Loc 1' FROM DUAL UNION ALL
SELECT 6, 'Item B', 'Loc 2' FROM DUAL UNION ALL
SELECT 7, 'Item B', 'Loc 3' FROM DUAL UNION ALL
SELECT 8, 'Item B', 'Loc 4' FROM DUAL UNION ALL
SELECT 9, 'Item C', 'Loc 1' FROM DUAL UNION ALL
SELECT 10, 'Item C', 'Loc 2' FROM DUAL UNION ALL
SELECT 11, 'Item C', 'Loc 3' FROM DUAL UNION ALL
SELECT 12, 'Item C', 'Loc 4' FROM DUAL;
CREATE TABLE b (item_id, description) AS
SELECT 1, 'Tube' FROM DUAL UNION ALL
SELECT 2, 'Pipe' FROM DUAL UNION ALL
SELECT 3, 'Pipe' FROM DUAL UNION ALL
SELECT 4, 'Pipe' FROM DUAL UNION ALL
SELECT 5, 'Mallet' FROM DUAL UNION ALL
SELECT 6, 'Mallet' FROM DUAL UNION ALL
SELECT 7, 'Mallet' FROM DUAL UNION ALL
SELECT 8, 'Mallet' FROM DUAL UNION ALL
SELECT 9, 'Wrench' FROM DUAL UNION ALL
SELECT 10, 'Spanner' FROM DUAL UNION ALL
SELECT 11, 'Spanner' FROM DUAL UNION ALL
SELECT 12, 'Spanner' FROM DUAL;
Оба вывода:
Другой способ решить эту проблему — использовать оператор case и оператор существования. но вам также нужен уникальный идентификатор двух таблиц (a, b)
with all_data as (
select a.*, b.description from a join b on a.item_id=b.item_id
), flag as (
select a.* , case when exists (
select * from all_data where item=a.item and a.location <location and a.description <> description)
then 1 else 0 end as flag
from all_data a
), grp as (
select a.*, sum(flag)over(partition by item order by location)as grp,
row_number()over(partition by item order by location)as rn_loc
from flag a
)
select item, location, description
from grp
where grp=1 and rn_loc<3;
Надеюсь, поможет.
Спасибо Флорин. Я опробую ваши предложения в ближайшие пару дней и оставлю отзывы.
Пожалуйста, сделайте это. Спасибо.
Привет Флорин. Да, мне это помогло. Конечно, мне пришлось немного подправить код, но да, это сработало. Спасибо. То же самое и с двумя другими предложениями. Еще раз спасибо.
Если у вас уже есть запрос, результат которого такой же, как в начале вопроса...
-- lets imagine this is your query
Select A.ITEM, A.LOCATION, B.DESCRIPTION
From A
Inner Join B ON ( /* your join condition(s) */ )
Order By A.ITEM, A.LOCATION
/*
ITEM LOCATION DESCRIPTION
------ ---------- -------------
Item A Loc 1 Tube
Item A Loc 2 Pipe
Item A Loc 3 Pipe
Item A Loc 4 Pipe
Item B Loc 1 Mallet
Item B Loc 2 Mallet
Item B Loc 3 Mallet
Item B Loc 4 Mallet
Item C Loc 1 Wrench
Item C Loc 2 Spanner
Item C Loc 3 Spanner
Item C Loc 4 Spanner
Item C Loc 5 Spanner
Item C Loc 6 Spanner
Item C Loc 7 Spanner */
... тогда вы могли бы объявить его sql как cte (назвав его all_data) и, используя только этот cte, получить результат...
WITH
all_data AS -- Your query's sql declared as cte named all_data
( Select A.ITEM, A.LOCATION, B.DESCRIPTION
From A
Inner Join B ON ( /* your join condition(s) */ )
Order By A.ITEM, A.LOCATION
)
-- M a i n S Q L :
Select a.ITEM, a.LOCATION, a.DESCRIPTION
From all_data a
Inner Join ( Select ITEM, DESCRIPTION
From all_data
Group By ITEM, DESCRIPTION
Having Count(Distinct LOCATION) = 1
) g ON( ( g.ITEM = a.ITEM And g.DESCRIPTION = a.DESCRIPTION And a.LOCATION = 'Loc 1')
OR
( g.ITEM = a.ITEM And g.DESCRIPTION != a.DESCRIPTION And a.LOCATION = 'Loc 2')
)
... подзапрос в основном sql будет извлекать только элементы, имеющие уникальное описание Loc 1 для каждого элемента, а условия включения соединения должны фильтровать конечный результат, который должен быть...
/* R e s u l t :
ITEM LOCATION DESCRIPTION
------ ---------- -------------
Item A Loc 1 Tube
Item A Loc 2 Pipe
Item C Loc 1 Wrench
Item C Loc 2 Spanner */
Спасибо, д р. Я опробую ваши предложения в ближайшие пару дней и оставлю отзывы.
Привет, доктор, Да, это сработало и для меня. Конечно, мне пришлось немного подправить код, но да, это сработало. Спасибо
@redoctober Если это нормально, вы можете проголосовать за все полезное и принять один из ответов, который лучше всего соответствует вашим потребностям.
Сделанный. Еще раз спасибо, доктор. Цените помощь и усилия.
@redoctober Хороший выбор, спасибо.
Пожалуйста, отредактируйте вопрос, включив в него минимальный воспроизводимый пример с утверждениями
CREATE TABLE
иINSERT
для вашего образца данных (текст, который мы можем скопировать, вставить и выполнить, а не изображения). На данный момент, судя по вашему описанию, между двумя таблицами не существует никаких ссылочных ограничений, если таблицаA
содержит только два столбцаitem
иlocation
, а таблицаB
содержит только один столбецdescription
, поэтому нет возможности соединить две таблицы. ; вам нужно иметь первичный ключ, а затем присоединиться на его основе.