postgresql 更新查询出现问题-我没有得到想要的结果

wvyml7n5  于 2023-05-17  发布在  PostgreSQL
关注(0)|答案(2)|浏览(999)

因此,我需要更新一个大学数据库中名为register的表中的几列,该表的名称为exam_grade、lab_grade和final grade。最终成绩是根据exam_grade和lab_grade的结果计算的,但只要lab_grade的结果为NULL,则final_grade的结果不会直接变为exam_grade,而是仍为NULL。下面是函数的代码:

CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
RETURNS void
AS
$$
DECLARE
       pointer record;
       percentage numeric;
       exam_i numeric;
       lab_i numeric;
BEGIN
     FOR pointer IN
                   (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
                           rg.serial_number, rg.register_status, 
                           cr.course_code, cr.lab_hours
                    FROM "Register" rg
                    JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
                    WHERE rg.register_status = 'approved' AND rg.serial_number = num)
                    LOOP
                        IF (pointer.exam_grade IS NULL) THEN
                            exam_i = floor((random()*(10-1)+1));
                        ELSE
                            exam_i = pointer.exam_grade;
                        END IF;
                        IF (pointer.lab_grade IS NULL AND  pointer.lab_hours > 0) THEN
                            lab_i = floor((random()*(10-1)+1));
                        ELSE
                            lab_i = pointer.lab_grade;
                        END IF;
                        percentage = (SELECT exam_percentage FROM "CourseRun" 
                                      WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
                        UPDATE "Register" r
                        SET lab_grade = lab_i ,exam_grade = exam_i,
                            final_grade = (SELECT
                                               CASE WHEN pointer.lab_hours IS NOT NULL 
                                               THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
                                               ELSE (exam_i)
                                               END)
                        WHERE (final_grade IS NULL)
                        AND r.amka = pointer.amka  
                        AND r.course_code = pointer.course_code
                        AND r.register_status = 'approved';
                        
                    END LOOP;
END;
$$

LANGUAGE 'plpgsql';
-- DROP TABLE IF EXISTS public."CourseRun";

CREATE TABLE IF NOT EXISTS public."CourseRun"
(
    course_code character(7) COLLATE pg_catalog."default" NOT NULL,
    serial_number integer NOT NULL,
    exam_min numeric,
    lab_min numeric,
    exam_percentage numeric,
    labuses integer,
    semesterrunsin integer NOT NULL,
    CONSTRAINT "CourseRun_pkey" PRIMARY KEY (course_code, serial_number),
    CONSTRAINT "CourseRun_course_code_fkey" FOREIGN KEY (course_code)
        REFERENCES public."Course" (course_code) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT "CourseRun_labuses_fkey" FOREIGN KEY (labuses)
        REFERENCES public."Lab" (lab_code) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT "CourseRun_semesterrunsin_fkey" FOREIGN KEY (semesterrunsin)
        REFERENCES public."Semester" (semester_id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS public."CourseRun"
    OWNER to postgres;```

```-- Table: public.Course

-- DROP TABLE IF EXISTS public."Course";

CREATE TABLE IF NOT EXISTS public."Course"
(
    course_code character(7) COLLATE pg_catalog."default" NOT NULL,
    course_title character(100) COLLATE pg_catalog."default" NOT NULL,
    units smallint NOT NULL,
    lecture_hours smallint NOT NULL,
    tutorial_hours smallint NOT NULL,
    lab_hours smallint NOT NULL,
    typical_year smallint NOT NULL,
    typical_season semester_season_type NOT NULL,
    obligatory boolean NOT NULL,
    course_description character varying COLLATE pg_catalog."default",
    CONSTRAINT "Course_pkey" PRIMARY KEY (course_code)
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS public."Course"
    OWNER to postgres;```

```-- Table: public.Register

-- DROP TABLE IF EXISTS public."Register";

CREATE TABLE IF NOT EXISTS public."Register"
(
    amka character varying COLLATE pg_catalog."default" NOT NULL,
    serial_number integer NOT NULL,
    course_code character(7) COLLATE pg_catalog."default" NOT NULL,
    exam_grade numeric,
    final_grade numeric,
    lab_grade numeric,
    register_status register_status_type,
    CONSTRAINT "Register_pkey" PRIMARY KEY (course_code, serial_number, amka),
    CONSTRAINT "Register_course_run_fkey" FOREIGN KEY (serial_number, course_code)
        REFERENCES public."CourseRun" (serial_number, course_code) MATCH SIMPLE
        ON UPDATE CASCADE
        ON DELETE CASCADE,
    CONSTRAINT "Register_student_fkey" FOREIGN KEY (amka)
        REFERENCES public."Student" (amka) MATCH SIMPLE
        ON UPDATE CASCADE
        ON DELETE CASCADE
        NOT VALID
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS public."Register"
    OWNER to postgres;```
amka|serial_number|course_code|exam_grade|final_grade|lab_grade|semes_status
"01010104188"   12  "ΑΓΓ 201"   6   6   10  "pass"
"01010104188"   12  "ΑΓΓ 202"   2           "approved"
"01010104188"   12  "ΗΡΥ 201"   8   9   10  "pass"
"01010104188"   12  "ΗΡΥ 202"   9   8   7   "pass"
"01010104188"   12  "ΗΡΥ 203"   7   8.40    9   "approved"
"01010104188"   12  "ΗΡΥ 204"   7   5.50    4   "approved"
"01010104188"   12  "ΗΡΥ 211"   9           "approved"
"01010104188"   12  "ΜΑΘ 107"   2   2   6   "fail"
"01010104188"   12  "ΠΛΗ 201"   7   0   2   "fail"
"01010104188"   12  "ΠΛΗ 202"   2   2.70    3   "approved"
"01010104188"   12  "ΠΛΗ 211"   8   7   5   "pass"
"01010104188"   12  "ΤΗΛ 201"   7   7   7   "pass"
"01010104188"   12  "ΤΗΛ 202"   4   3.20    2   "approved"
"01010104188"   12  "ΤΗΛ 211"   5   7.00    9   "approved"

任何帮助都将不胜感激,如果需要添加任何内容,以便您获得更好的视角,请这样说。
我尝试了许多不同的方法来编写查询,每次的结果都是一样的。当lab_grade为NULL时,我无法获取final_grade = exam_ grade。我没有收到任何错误消息,所以逻辑有问题。

hs1ihplo

hs1ihplo1#

您可以使用COALESCE或签入您的CASE

CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
RETURNS void
AS
$$
DECLARE
       pointer record;
       percentage numeric;
       exam_i numeric;
       lab_i numeric;
BEGIN
     FOR pointer IN
                   (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
                           rg.serial_number, rg.register_status, 
                           cr.course_code, cr.lab_hours
                    FROM "Register" rg
                    JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
                    WHERE rg.register_status = 'approved' AND rg.serial_number = num)
                    LOOP
                        IF (pointer.exam_grade IS NULL) THEN
                            exam_i = floor((random()*(10-1)+1));
                        ELSE
                            exam_i = pointer.exam_grade;
                        END IF;
                        IF (pointer.lab_grade IS NULL AND  pointer.lab_hours > 0) THEN
                            lab_i = floor((random()*(10-1)+1));
                        ELSE
                            lab_i = pointer.lab_grade;
                        END IF;
                        percentage = (SELECT exam_percentage FROM "CourseRun" 
                                      WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
                        UPDATE "Register" r
                        SET lab_grade = lab_i ,exam_grade = exam_i,
                            final_grade = (SELECT
                                               CASE WHEN pointer.lab_hours IS NOT NULL 
                                               THEN (floor(((COALESCE(lab_i, 0)*(100-percentage)) + exam_i * percentage)/100))
                                               ELSE (exam_i)
                                               END)
                        WHERE (final_grade IS NULL)
                        AND r.amka = pointer.amka  
                        AND r.course_code = pointer.course_code
                        AND r.register_status = 'approved';
                        
                    END LOOP;
END;
$$

LANGUAGE 'plpgsql';

CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
RETURNS void
AS
$$
DECLARE
       pointer record;
       percentage numeric;
       exam_i numeric;
       lab_i numeric;
BEGIN
     FOR pointer IN
                   (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
                           rg.serial_number, rg.register_status, 
                           cr.course_code, cr.lab_hours
                    FROM "Register" rg
                    JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
                    WHERE rg.register_status = 'approved' AND rg.serial_number = num)
                    LOOP
                        IF (pointer.exam_grade IS NULL) THEN
                            exam_i = floor((random()*(10-1)+1));
                        ELSE
                            exam_i = pointer.exam_grade;
                        END IF;
                        IF (pointer.lab_grade IS NULL AND  pointer.lab_hours > 0) THEN
                            lab_i = floor((random()*(10-1)+1));
                        ELSE
                            lab_i = pointer.lab_grade;
                        END IF;
                        percentage = (SELECT exam_percentage FROM "CourseRun" 
                                      WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
                        UPDATE "Register" r
                        SET lab_grade = lab_i ,exam_grade = exam_i,
                            final_grade = (SELECT
                                               CASE WHEN pointer.lab_hours IS NOT NULL AND lab_i IS NOT NULL
                                               THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
                                               ELSE (exam_i)
                                               END)
                        WHERE (final_grade IS NULL)
                        AND r.amka = pointer.amka  
                        AND r.course_code = pointer.course_code
                        AND r.register_status = 'approved';
                        
                    END LOOP;
END;
$$

LANGUAGE 'plpgsql';
arknldoa

arknldoa2#

您的子查询是我们需要检查问题所在的地方,因为,由于您抱怨错误的值导致更新而不是缺少值更改。因此,让我们看看这个子查询:

SELECT
CASE WHEN pointer.lab_hours IS NOT NULL 
     THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
     ELSE (exam_i)
END

NULL是一个absorbing element,所以,无论你对它执行什么操作,结果都是NULL。原因很简单:NULL是缺少值,或者换句话说,它是未知。那么,结果是什么

未知+ 2

比如说?当然,这是未知的。
因此,在不太了解您正在测试的数据的情况下,这些字段可能具有NULL值:

  • lab_i
  • percentage
  • exam_i

因此,您可能需要确定默认值应该是什么,并使用这样的默认值作为COALESCE调用的参数,其形式为COALESCE(<your field or expression>, <the preferred default>)

相关问题