#sql #oracle #select
#sql #Oracle #выберите
Вопрос:
У меня настроена таблица со столбцами:
- fname
- lname
- адрес
- город
- состояние
- zip
- Идентификатор клиента
- date_modified
данные в основном денормализованы, поэтому выглядят так
Бен -- Смит--*** 123first*** st -- Нью-Йорк -- Нью-Йорк -- 12101 -- 123 -- 1-1-2011 Бен -- Смит--*** 123 1-й ст *** -- Нью-Йорк -- Нью-Йорк -- 12101 -- 123 -- 1-1-2011 Сара - Смит - БЛА-БЛА-БЛА
Я пытаюсь скопировать эти записи в новую таблицу, но мне нужна только одна запись для каждого идентификатора клиента.
Я попытался сделать что-то вроде
insert into new_table(fname,lname,address,city,state,zip,Customer_ID,
date_modified)
select fname,lname,address,city,state,zip,Customer_ID,date_modified
group by (fname,lname,address,city,state,zip,Customer_ID,date_modified)
проблема в том, что слишком много адресов и других столбцов имеют одинаковое значение, но разный текст (первый против 1-го). таким образом, group by оставляет обе эти записи в новой таблице. как мне получить одну запись для каждого идентификатора клиента, выбрав максимальное значение (дата изменения). В принципе, я бы хотел группировать только по идентификатору customer_id, а не по остальным столбцам, но это не разрешено в oracle.
Комментарии:
1. Обратите внимание, что
group by
это не функция. Скобки совершенно бесполезны.2. Вам будет лучше всего изменить дизайн вашей базы данных, с этим есть некоторые проблемы. В зависимости от необходимости: 1) Разделите адрес на его собственную таблицу, затем создайте таблицу перекрестных ссылок между адресом и клиентом. 2) Отделите имя от его собственной таблицы, затем таблицу перекрестных ссылок между именем и клиентом со столбцом для ‘part_of_name’ (т.Е. — family, given, nick и т. Д.).
Ответ №1:
Ниже приведен один из нескольких способов получить то, что вы, кажется, хотите. Имейте в виду, однако, что это не нормализует вашу базу данных. У вас все еще есть customer_id
вход с именем, фамилией и адресом. Я бы, вероятно, превратил это в несколько вставок, одну, чтобы получить все уникальные идентификаторы клиентов вместе с последней информацией об именах для таблицы Customers, а затем другую вставку для адресов. Если вам нужна историческая информация об изменениях, вам нужно будет соответствующим образом настроить.
Кроме того, приведенный ниже код не будет работать должным образом, если у вас есть две строки, которые имеют одинаковый точный идентификатор клиента и одинаковый точный date_modified
. Если вы столкнетесь с этим случаем, вам нужно будет придумать соответствующую бизнес-логику для обработки этого.
INSERT INTO New_Table (
fname,
lname,
address,
city,
state,
zip,
Customer_ID,
date_modified )
SELECT
OT1.fname,
OT1.lname,
OT1.address,
OT1.city,
OT1.state,
OT1.zip,
OT1.customer_id,
OT1.date_modified
FROM
(
SELECT
customer_id,
MAX(date_modified) AS latest_date_modified
FROM
Old_Table
GROUP BY customer_id) SQ
INNER JOIN Old_Table OT1 ON
OT1.customer_id = OT1.customer_id AND
OT1.date_modified = SQ.latest_date_modified
Ответ №2:
Это довольно просто, используя аналитические (или оконные) функции для выбора первой строки для каждого клиента. В случае, если две строки имеют одинаковую date_modified , не определено, какая из них берется.
INSERT INTO new_table (fname,lname,address,city,state,zip,Customer_ID,date_modified)
SELECT fname,
lname,
address,
city,
state,
zip,
Customer_ID,
date_modified
FROM (
SELECT fname,
lname,
address,
city,
state,
zip,
Customer_ID,
date_modified,
row_number() over (partition by customer_id order by date_modified desc) as rn
)
WHERE rn = 1