问题更新查询 – 我没有得到我想要的结果。

huangapple go评论102阅读模式
英文:

Problem with update query - I don't get the results I want

问题

I understand your request. Here's the translated code:

  1. 我负责一个大学的数据库,我需要更新一个名为register的表的几个列,这些列的名称分别是exam_gradelab_gradefinal_gradefinal_grade是基于exam_gradelab_grade的结果计算的,但是当lab_grade的结果为NULLfinal_grade的结果不应该直接等于exam_grade,而应该保持为NULL。以下是该函数的代码:
  2. ```sql
  3. DROP FUNCTION public.fn_question_2_2(integer);
  4. CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
  5. RETURNS void
  6. AS
  7. $$
  8. DECLARE
  9. pointer record;
  10. percentage numeric;
  11. exam_i numeric;
  12. lab_i numeric;
  13. BEGIN
  14. FOR pointer IN
  15. (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
  16. rg.serial_number, rg.register_status,
  17. cr.course_code, cr.lab_hours
  18. FROM "Register" rg
  19. JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
  20. WHERE rg.register_status = 'approved' AND rg.serial_number = num)
  21. LOOP
  22. IF (pointer.exam_grade IS NULL) THEN
  23. exam_i = floor((random()*(10-1)+1));
  24. ELSE
  25. exam_i = pointer.exam_grade;
  26. END IF;
  27. IF (pointer.lab_grade IS NULL AND pointer.lab_hours > 0) THEN
  28. lab_i = floor((random()*(10-1)+1));
  29. ELSE
  30. lab_i = pointer.lab_grade;
  31. END IF;
  32. percentage = (SELECT exam_percentage FROM "CourseRun"
  33. WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
  34. UPDATE "Register" r
  35. SET lab_grade = lab_i ,exam_grade = exam_i,
  36. final_grade = (SELECT
  37. CASE WHEN pointer.lab_hours IS NOT NULL
  38. THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
  39. ELSE (exam_i)
  40. END)
  41. WHERE (final_grade IS NULL)
  42. AND r.amka = pointer.amka
  43. AND r.course_code = pointer.course_code
  44. AND r.register_status = 'approved';
  45. END LOOP;
  46. END;
  47. $$
  48. LANGUAGE 'plpgsql';
  1. -- Table: public.CourseRun
  2. -- DROP TABLE IF EXISTS public."CourseRun";
  3. CREATE TABLE IF NOT EXISTS public."CourseRun"
  4. (
  5. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  6. serial_number integer NOT NULL,
  7. exam_min numeric,
  8. lab_min numeric,
  9. exam_percentage numeric,
  10. labuses integer,
  11. semesterrunsin integer NOT NULL,
  12. CONSTRAINT "CourseRun_pkey" PRIMARY KEY (course_code, serial_number),
  13. CONSTRAINT "CourseRun_course_code_fkey" FOREIGN KEY (course_code)
  14. REFERENCES public."Course" (course_code) MATCH SIMPLE
  15. ON UPDATE NO ACTION
  16. ON DELETE NO ACTION,
  17. CONSTRAINT "CourseRun_labuses_fkey" FOREIGN KEY (labuses)
  18. REFERENCES public."Lab" (lab_code) MATCH SIMPLE
  19. ON UPDATE NO ACTION
  20. ON DELETE NO ACTION,
  21. CONSTRAINT "CourseRun_semesterrunsin_fkey" FOREIGN KEY (semesterrunsin)
  22. REFERENCES public."Semester" (semester_id) MATCH SIMPLE
  23. ON UPDATE NO ACTION
  24. ON DELETE NO ACTION
  25. )
  26. TABLESPACE pg_default;
  27. ALTER TABLE IF EXISTS public."CourseRun"
  28. OWNER to postgres;
  1. -- Table: public.Course
  2. -- DROP TABLE IF EXISTS public."Course";
  3. CREATE TABLE IF NOT EXISTS public."Course"
  4. (
  5. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  6. course_title character(100) COLLATE pg_catalog."default" NOT NULL,
  7. units smallint NOT NULL,
  8. lecture_hours smallint NOT NULL,
  9. tutorial_hours smallint NOT NULL,
  10. lab_hours smallint NOT NULL,
  11. typical_year smallint NOT NULL,
  12. typical_season semester_season_type NOT NULL,
  13. obligatory boolean NOT NULL,
  14. course_description character varying COLLATE pg_catalog."default",
  15. CONSTRAINT "Course_pkey" PRIMARY KEY (course_code)
  16. )
  17. TABLESPACE pg_default;
  18. ALTER TABLE IF EXISTS public."Course"
  19. OWNER to postgres;
  1. -- Table: public.Register
  2. -- DROP TABLE IF EXISTS public."Register";
  3. CREATE TABLE IF NOT EXISTS public."Register"
  4. (
  5. amka character varying COLLATE pg_catalog."default" NOT NULL,
  6. serial_number integer NOT NULL,
  7. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  8. exam_grade numeric,
  9. final_grade numeric,
  10. lab_grade numeric,
  11. register_status register_status_type,
  12. CONSTRAINT "Register_pkey" PRIMARY KEY (course_code, serial_number, amka),
  13. CONSTRAINT "Register_course_run_fkey" FOREIGN KEY (serial_number, course_code)
  14. REFERENCES public."CourseRun" (serial_number, course_code) MATCH SIMPLE
  15. ON UPDATE CASCADE
  16. ON DELETE CASCADE,
  17. CONSTRAINT "Register_student_fkey" FOREIGN KEY (amka)
  18. REFERENCES public."Student" (amka) MATCH SIMPLE
  19. ON UPDATE CASCADE
  20. ON DELETE CASCADE
  21. NOT VALID
  22. )
  23. TABLESPACE pg_default;
  24. ALTER TABLE IF EXISTS public."Register"
  25. OWNER to postgres;

希望对你有所帮助。

英文:

So I database for a university and I need to update several columns of a table named register going with the name of exam_grade, lab_grade, and final grade. The final grade is calculated based on the results of exam_grade and lab_grade, but whenever the result of lab_grade is NULL then the result of final_grade is not becoming directly the exam_grade, but also stays NULL. Here is the code for the function:

  1. CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
  2. RETURNS void
  3. AS
  4. $$
  5. DECLARE
  6. pointer record;
  7. percentage numeric;
  8. exam_i numeric;
  9. lab_i numeric;
  10. BEGIN
  11. FOR pointer IN
  12. (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
  13. rg.serial_number, rg.register_status,
  14. cr.course_code, cr.lab_hours
  15. FROM "Register" rg
  16. JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
  17. WHERE rg.register_status = 'approved' AND rg.serial_number = num)
  18. LOOP
  19. IF (pointer.exam_grade IS NULL) THEN
  20. exam_i = floor((random()*(10-1)+1));
  21. ELSE
  22. exam_i = pointer.exam_grade;
  23. END IF;
  24. IF (pointer.lab_grade IS NULL AND pointer.lab_hours > 0) THEN
  25. lab_i = floor((random()*(10-1)+1));
  26. ELSE
  27. lab_i = pointer.lab_grade;
  28. END IF;
  29. percentage = (SELECT exam_percentage FROM "CourseRun"
  30. WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
  31. UPDATE "Register" r
  32. SET lab_grade = lab_i ,exam_grade = exam_i,
  33. final_grade = (SELECT
  34. CASE WHEN pointer.lab_hours IS NOT NULL
  35. THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
  36. ELSE (exam_i)
  37. END)
  38. WHERE (final_grade IS NULL)
  39. AND r.amka = pointer.amka
  40. AND r.course_code = pointer.course_code
  41. AND r.register_status = 'approved';
  42. END LOOP;
  43. END;
  44. $$
  45. LANGUAGE 'plpgsql';
  1. -- DROP TABLE IF EXISTS public."CourseRun";
  2. CREATE TABLE IF NOT EXISTS public."CourseRun"
  3. (
  4. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  5. serial_number integer NOT NULL,
  6. exam_min numeric,
  7. lab_min numeric,
  8. exam_percentage numeric,
  9. labuses integer,
  10. semesterrunsin integer NOT NULL,
  11. CONSTRAINT "CourseRun_pkey" PRIMARY KEY (course_code, serial_number),
  12. CONSTRAINT "CourseRun_course_code_fkey" FOREIGN KEY (course_code)
  13. REFERENCES public."Course" (course_code) MATCH SIMPLE
  14. ON UPDATE NO ACTION
  15. ON DELETE NO ACTION,
  16. CONSTRAINT "CourseRun_labuses_fkey" FOREIGN KEY (labuses)
  17. REFERENCES public."Lab" (lab_code) MATCH SIMPLE
  18. ON UPDATE NO ACTION
  19. ON DELETE NO ACTION,
  20. CONSTRAINT "CourseRun_semesterrunsin_fkey" FOREIGN KEY (semesterrunsin)
  21. REFERENCES public."Semester" (semester_id) MATCH SIMPLE
  22. ON UPDATE NO ACTION
  23. ON DELETE NO ACTION
  24. )
  25. TABLESPACE pg_default;
  26. ALTER TABLE IF EXISTS public."CourseRun"
  27. OWNER to postgres;```
  28. ```-- Table: public.Course
  29. -- DROP TABLE IF EXISTS public."Course";
  30. CREATE TABLE IF NOT EXISTS public."Course"
  31. (
  32. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  33. course_title character(100) COLLATE pg_catalog."default" NOT NULL,
  34. units smallint NOT NULL,
  35. lecture_hours smallint NOT NULL,
  36. tutorial_hours smallint NOT NULL,
  37. lab_hours smallint NOT NULL,
  38. typical_year smallint NOT NULL,
  39. typical_season semester_season_type NOT NULL,
  40. obligatory boolean NOT NULL,
  41. course_description character varying COLLATE pg_catalog."default",
  42. CONSTRAINT "Course_pkey" PRIMARY KEY (course_code)
  43. )
  44. TABLESPACE pg_default;
  45. ALTER TABLE IF EXISTS public."Course"
  46. OWNER to postgres;```
  47. ```-- Table: public.Register
  48. -- DROP TABLE IF EXISTS public."Register";
  49. CREATE TABLE IF NOT EXISTS public."Register"
  50. (
  51. amka character varying COLLATE pg_catalog."default" NOT NULL,
  52. serial_number integer NOT NULL,
  53. course_code character(7) COLLATE pg_catalog."default" NOT NULL,
  54. exam_grade numeric,
  55. final_grade numeric,
  56. lab_grade numeric,
  57. register_status register_status_type,
  58. CONSTRAINT "Register_pkey" PRIMARY KEY (course_code, serial_number, amka),
  59. CONSTRAINT "Register_course_run_fkey" FOREIGN KEY (serial_number, course_code)
  60. REFERENCES public."CourseRun" (serial_number, course_code) MATCH SIMPLE
  61. ON UPDATE CASCADE
  62. ON DELETE CASCADE,
  63. CONSTRAINT "Register_student_fkey" FOREIGN KEY (amka)
  64. REFERENCES public."Student" (amka) MATCH SIMPLE
  65. ON UPDATE CASCADE
  66. ON DELETE CASCADE
  67. NOT VALID
  68. )
  69. TABLESPACE pg_default;
  70. ALTER TABLE IF EXISTS public."Register"
  71. OWNER to postgres;```
  1. amka|serial_number|course_code|exam_grade|final_grade|lab_grade|semes_status
  2. "01010104188" 12 "ΑΓΓ 201" 6 6 10 "pass"
  3. "01010104188" 12 "ΑΓΓ 202" 2 "approved"
  4. "01010104188" 12 "ΗΡΥ 201" 8 9 10 "pass"
  5. "01010104188" 12 "ΗΡΥ 202" 9 8 7 "pass"
  6. "01010104188" 12 "ΗΡΥ 203" 7 8.40 9 "approved"
  7. "01010104188" 12 "ΗΡΥ 204" 7 5.50 4 "approved"
  8. "01010104188" 12 "ΗΡΥ 211" 9 "approved"
  9. "01010104188" 12 "ΜΑΘ 107" 2 2 6 "fail"
  10. "01010104188" 12 "ΠΛΗ 201" 7 0 2 "fail"
  11. "01010104188" 12 "ΠΛΗ 202" 2 2.70 3 "approved"
  12. "01010104188" 12 "ΠΛΗ 211" 8 7 5 "pass"
  13. "01010104188" 12 "ΤΗΛ 201" 7 7 7 "pass"
  14. "01010104188" 12 "ΤΗΛ 202" 4 3.20 2 "approved"
  15. "01010104188" 12 "ΤΗΛ 211" 5 7.00 9 "approved"

Any help will be appreciated, and if anything needs to be added so that you get a better perspective please say so.

I tried many different ways of writing the query and the results are every time the same. I cannot get the final_grade = exam_ grade when the lab_grade is NULL. I don't get any error message so there is a problem with the logic.

答案1

得分: 1

你可以使用 COALESCE 或在你的 CASE 语句中进行检查:

英文:

You can either use COALESCE or check in your CASE:

  1. CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
  2. RETURNS void
  3. AS
  4. $$
  5. DECLARE
  6. pointer record;
  7. percentage numeric;
  8. exam_i numeric;
  9. lab_i numeric;
  10. BEGIN
  11. FOR pointer IN
  12. (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
  13. rg.serial_number, rg.register_status,
  14. cr.course_code, cr.lab_hours
  15. FROM "Register" rg
  16. JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
  17. WHERE rg.register_status = 'approved' AND rg.serial_number = num)
  18. LOOP
  19. IF (pointer.exam_grade IS NULL) THEN
  20. exam_i = floor((random()*(10-1)+1));
  21. ELSE
  22. exam_i = pointer.exam_grade;
  23. END IF;
  24. IF (pointer.lab_grade IS NULL AND pointer.lab_hours > 0) THEN
  25. lab_i = floor((random()*(10-1)+1));
  26. ELSE
  27. lab_i = pointer.lab_grade;
  28. END IF;
  29. percentage = (SELECT exam_percentage FROM "CourseRun"
  30. WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
  31. UPDATE "Register" r
  32. SET lab_grade = lab_i ,exam_grade = exam_i,
  33. final_grade = (SELECT
  34. CASE WHEN pointer.lab_hours IS NOT NULL
  35. THEN (floor(((COALESCE(lab_i, 0)*(100-percentage)) + exam_i * percentage)/100))
  36. ELSE (exam_i)
  37. END)
  38. WHERE (final_grade IS NULL)
  39. AND r.amka = pointer.amka
  40. AND r.course_code = pointer.course_code
  41. AND r.register_status = 'approved';
  42. END LOOP;
  43. END;
  44. $$
  45. LANGUAGE 'plpgsql';

or

  1. CREATE OR REPLACE FUNCTION public.fn_question_2_2(num integer)
  2. RETURNS void
  3. AS
  4. $$
  5. DECLARE
  6. pointer record;
  7. percentage numeric;
  8. exam_i numeric;
  9. lab_i numeric;
  10. BEGIN
  11. FOR pointer IN
  12. (SELECT rg.amka, rg.lab_grade, rg.exam_grade,
  13. rg.serial_number, rg.register_status,
  14. cr.course_code, cr.lab_hours
  15. FROM "Register" rg
  16. JOIN (SELECT course_code, lab_hours FROM "Course") cr USING (course_code)
  17. WHERE rg.register_status = 'approved' AND rg.serial_number = num)
  18. LOOP
  19. IF (pointer.exam_grade IS NULL) THEN
  20. exam_i = floor((random()*(10-1)+1));
  21. ELSE
  22. exam_i = pointer.exam_grade;
  23. END IF;
  24. IF (pointer.lab_grade IS NULL AND pointer.lab_hours > 0) THEN
  25. lab_i = floor((random()*(10-1)+1));
  26. ELSE
  27. lab_i = pointer.lab_grade;
  28. END IF;
  29. percentage = (SELECT exam_percentage FROM "CourseRun"
  30. WHERE course_code = pointer.course_code AND serial_number = pointer.serial_number);
  31. UPDATE "Register" r
  32. SET lab_grade = lab_i ,exam_grade = exam_i,
  33. final_grade = (SELECT
  34. CASE WHEN pointer.lab_hours IS NOT NULL AND lab_i IS NOT NULL
  35. THEN (floor(((lab_i*(100-percentage)) + exam_i * percentage)/100))
  36. ELSE (exam_i)
  37. END)
  38. WHERE (final_grade IS NULL)
  39. AND r.amka = pointer.amka
  40. AND r.course_code = pointer.course_code
  41. AND r.register_status = 'approved';
  42. END LOOP;
  43. END;
  44. $$
  45. LANGUAGE 'plpgsql';

答案2

得分: 0

你的子查询是我们需要检查问题的地方,因为你抱怨的是错误的数值导致了更新,而不是数值变化的缺失。因此,让我们看看这个子查询:

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

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

未知 + 2

的结果是什么呢?自然是未知。

因此,如果不太了解你正在测试的数据,以下是可能具有 NULL 值的字段:

  • lab_i
  • percentage
  • exam_i

因此,你可能需要弄清楚默认值应该是什么,并将这样的默认值用作对 COALESCE 的调用的参数,形式为 COALESCE(<你的字段或表达式>, <首选默认值>)

英文:

Your subquery is the place where we need to check what the problem is, because, since you complained on the wrong value resulting in the update and not a lack of value change. Hence, let's see this subquery:

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

NULL is an absorbing element, so, whatever operation you perform with it, the result will be NULL. The reason is simple: NULL is the lack of value, or, in other words, it is the unknown. So, what's the result of

unkown + 2

for example? Naturally, it's unknown.

So, without knowing too much about the data you are testing, these are the fields that could have a NULL value:

  • lab_i
  • percentage
  • exam_i

So, you will likely need to figure out what the default value should be and use such a default value as a parameter to a call for COALESCE, of the form of COALESCE(&lt;your field or expression&gt;, &lt;the preferred default&gt;)

huangapple
  • 本文由 发表于 2023年5月6日 23:23:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76189681.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定