#sql #oracle #window-functions
#sql #Oracle #окно-функции
Вопрос:
У меня есть таблица, вызываемая Student
с этими столбцами:
First name
Last name
Class ID
Class
Я хочу создать идентификатор для student, я пытался использовать Row_number Over Partiton
, но, похоже, я не получаю то, что ищу, но большая часть его сбрасывается, это результат, который я пытаюсь получить.
First Last Class ClasID ID (outcome looking for)
------------------------------------
John Brown Math M21 ID01
John Brown English E31 ID01
Tom Bank Math M21 ID02
John Brown Gym G41 ID01
Tim Brown English E31 ID03
Комментарии:
1. Эта таблица не должна вызываться
Student
в первую очередь. Должно быть три таблицы:Student
(по одной строке на каждого учащегося, с индивидуальными данными для каждого учащегося, включая astudent_id
),Class
(по одной строке на класс, с характеристиками каждого класса, включая aclass_id
), и таблица, подобная той, которую вы проиллюстрировали, называется, возможноStudent_Class
, перечисляя только пары(student_id, class_id)
, чтобы показать, какие классыкаждый студент зачислен. Итак, вопрос: это то, что вы придумали? Это назначение в вашем классе?2. Если это задание, я бы сказал преподавателю, что это плохая модель данных, и нас не следует поощрять к обучению на плохих моделях данных. Если это то, что вы придумали, вы можете пересмотреть свой подход.
Ответ №1:
Используйте dense_rank()
:
select t.*, dense_rank() over(order by last, first) as id
from student
Это присваивает то же id
самое строкам, в которых имена и фамилии совпадают.
Если вам действительно нужен формат, подобный IDnn
(что, на мой взгляд, не имеет большого смысла), то вы можете отформатировать и объединить:
select t.*,
'ID' || to_char(dense_rank() over(order by last, first), '09') as id
from student
При этом не удастся сгенерировать правильную строку, если имеется более 99 разных учащихся.
Ответ №2:
Решение dense_rank, предлагаемое @GMB, создает «идентификатор» как часть заданного набора результатов, а не как неотъемлемый идентификатор данного учащегося. Классический метод постоянного присвоения идентификатора объекту (учащемуся, сотруднику, классу и т. Д.) Заключается в создании ПОСЛЕДОВАТЕЛЬНОСТИ, А затем ТРИГГЕРА on_insert для заполнения столбца ID значением next_value последовательности.
SQL> CREATE TABLE STUDENTS
2 (
3 STUDENT_ID NUMBER NOT NULL
4 , FIRST_NAME VARCHAR2(20)
5 , LAST_NAME VARCHAR2(20)
6 , CONSTRAINT STUDENTS_PK PRIMARY KEY
7 (
8 STUDENT_ID
9 )
10 ENABLE
11 );
Table created.
Elapsed: 00:00:00.05
SQL> --
SQL> CREATE SEQUENCE id_seq
2 START WITH 1
3 INCREMENT BY 1
4 ;
Sequence created.
Elapsed: 00:00:00.01
SQL> CREATE OR REPLACE TRIGGER STUDENTS_TRIG
2 BEFORE INSERT ON students
3 FOR EACH ROW
4 BEGIN
5 :new.student_ID := ID_SEQ.NEXTVAL;
6 END;
7 /
Trigger created.
Elapsed: 00:00:00.02
SQL> show errors
No errors.
SQL> --
SQL> insert into students (first_name,
2 last_name)
3 values ('Ed',
4 'Stevens'
5 )
6 ;
1 row created.
Elapsed: 00:00:00.18
SQL> commit;
Commit complete.
Elapsed: 00:00:00.01
SQL> select * from students;
STUDENT_ID FIRST_NAME LAST_NAME
---------- -------------------- --------------------
1 Ed Stevens
1 row selected.
Elapsed: 00:00:00.07
SQL> --
SQL> drop trigger students_trig;
Trigger dropped.
Elapsed: 00:00:00.02
SQL> drop table students purge;
Table dropped.
Elapsed: 00:00:00.05
SQL> drop sequence id_seq;
Sequence dropped.
Elapsed: 00:00:00.01
Начиная с версии 12, вам не нужно создавать последовательность или триггер, просто объявите столбец ID столбцом ‘identity’. Я оставляю это в качестве упражнения для студента, чтобы исследовать эту концепцию.