我继承了PostgreSQL 9.2.4数据库,虽然我在SQL Server中有相当广泛的背景,但我遇到的问题仍然存在一些问题。
我有一个表中有三个字段(包括其他内容)。 “age_years”,“age_months”和“age_days”。如果表中的某人是2个月或更小,那么他们在“age_days”字段中的值为他们的天数。如果他们不到3岁但超过2个月,那么他们在“age_months”字段中有一个值。任何超过3的东西,它们在“age_years”字段中都有一个值。
给定记录在这三个字段之一中仅具有非零值。例如,age_days和age_years都不会有非零值的情况。这些记录代表医院就诊,年龄是访问时个人的年龄。
在另一个表格中,我有几个字符不同的[]字段,最多包含20个值。它们是ref_age_cd,ref_age,ref_clow和ref_chigh。以下是该表中的示例记录(仅出于显示目的,其值小于最大值):
我为下面的丑陋线路道歉。我似乎无法让他们在一个非常易读的条件下进行格式化。
ref_age_cd | ref_age | ref_clow | ref_chigh
[D,D,D,M,M,Y,Y,Y] [1,4,15,2,7,13,18,199] [9.1,9.8,5.4,5.5,7.9,5.1,4.8,4.8] [27.1,27.8,16.4,15.8,15.9,11.1,10.8,10.8]
ref_age_cd字段确定您正在查看的年龄(天,月或年)。 ref_age确定该值,然后根据这两个值从ref_clow和ref_chigh字段中获取低值和高值。因此,例如,如果某人在age_months字段中有一个13,那么您将查看ref_age_cd并在数组中找到“M”值,然后查看相应的ref_age字段并找到低于该值的最大值。 age_months字段。因此,数组索引将为5.然后,您将获取ref_clow和ref_chigh字段中的第五个值以获取低值和高值。 (分别为7.9和15.9)
如果有人在10天之后,要查看的数组索引将为2(ref_age_cd为'D',ref_age为4)。这表明低值和高值分别为9.8和27.8。如果它们是80岁,则索引为7(ref_age_cd为'Y',ref_age为18)。低值和高值分别为4.8和10.8。
我无法弄清楚如何对此进行编程,所以当我从表A(带有age_days,age_months或age_years字段)加入到引用表时,我可以为ref_clow和ref_chigh拉出正确的数组索引。
我还应该提一下,我无法对此数据库进行任何更改。我需要用我所获得的东西来完成这项工作。
答案 0 :(得分:0)
对于单个患者,尝试这样的事情:
/* Creating test environment
CREATE TABLE refs (
id serial NOT NULL,
ref_age_cd character(1)[],
ref_age integer[],
ref_clow double precision[],
ref_chigh double precision[],
CONSTRAINT refs_pkey PRIMARY KEY (id)
);
INSERT INTO refs(ref_age_cd, ref_age, ref_clow, ref_chigh)
VALUES ('{"D","D","D","M","M","Y","Y","Y"}',
'{1,4,15,2,7,13,18,199}',
'{9.1,9.8,5.4,5.5,7.9,5.1,4.8,4.8}',
'{27.1,27.8,16.4,15.8,15.9,11.1,10.8,10.8}');
CREATE TABLE pats (
id serial NOT NULL,
name varchar(255) NOT NULL,
age_years integer,
age_months integer,
age_days integer,
CONSTRAINT pats_pkey PRIMARY KEY (id)
);
INSERT INTO pats
VALUES (DEFAULT, 'newborn', NULL, NULL, 10),
(DEFAULT, 'baby', NULL, 13, NULL),
(DEFAULT, 'adult', 80, NULL, NULL);
*/
-- Replace filters here to select only one row...
WITH tt AS ( SELECT * FROM refs WHERE id = 1 )
SELECT w.*, ref_clow, ref_chigh
FROM ( SELECT row_number() OVER () AS nr, unnest AS ref_age_cd
FROM UNNEST( (SELECT ref_age_cd FROM tt ) ), tt ) q1
JOIN ( SELECT row_number() OVER () AS nr, unnest AS ref_age
FROM UNNEST( (SELECT ref_age FROM tt ) ), tt ) q2 USING ( nr )
JOIN ( SELECT row_number() OVER () AS nr, unnest AS ref_clow
FROM UNNEST( (SELECT ref_clow FROM tt ) ), tt ) q3 USING ( nr )
JOIN ( SELECT row_number() OVER () AS nr, unnest AS ref_chigh
FROM UNNEST( (SELECT ref_chigh FROM tt ) ), tt ) q4 USING ( nr )
JOIN ( SELECT id, name, age_years, age_months, age_days,
CASE WHEN age_years IS NOT NULL THEN 'Y'
WHEN age_months IS NOT NULL THEN 'M'
WHEN age_days IS NOT NULL THEN 'D' END AS ref_age_cd,
CASE WHEN age_years IS NOT NULL THEN age_years
WHEN age_months IS NOT NULL THEN age_months
WHEN age_days IS NOT NULL THEN age_days END AS age
-- Replace filters here to select only one row...
FROM pats WHERE id = 2
) w USING (ref_age_cd)
WHERE ref_age <= age
ORDER BY ref_age DESC
LIMIT 1;
输出:
2;"baby";<NULL>;13;<NULL>;"M";13;7.9;15.9
答案 1 :(得分:0)
这最终成功了。发布,以便其他人也可以使用它。
--test data in first two "with" statements
with a AS (
select 1 AS patient_nr, CAST(2 AS INT) AS age_days, CAST(NULL AS INT) AS age_months, CAST(NULL AS INT) AS age_years
UNION ALL
select 2 AS patient_nr, CAST(16 AS INT) AS age_days, CAST(NULL AS INT) AS age_months, CAST(NULL AS INT) AS age_years
UNION ALL
select 3 AS patient_nr, CAST(NULL AS INT) AS age_days, CAST(13 AS INT) AS age_months, CAST(NULL AS INT) AS age_years
UNION ALL
select 4 AS patient_nr, CAST(10 AS INT) AS age_days, CAST(NULL AS INT) AS age_months, CAST(NULL AS INT) AS age_years
UNION ALL
select 5 AS patient_nr, CAST(NULL AS INT) AS age_days, CAST(NULL AS INT) AS age_months, CAST(80 AS INT) AS age_years
), b as (
SELECT ARRAY['D','D','D','M','M','Y','Y','Y'] AS ref_age_cd
, ARRAY[1,4,15,2,7,13,18,199] AS ref_age
, ARRAY[9.1,9.8,5.4,5.5,7.9,5.1,4.8,4.8] AS ref_clow
, ARRAY[27.1,27.8,16.4,15.8,15.9,11.1,10.8,10.8] AS ref_chigh
), refTable AS (
SELECT unnest(ref_age_cd) ref_age_cd
, unnest(ref_age) ref_age
, unnest(ref_clow) ref_clow
, unnest(ref_chigh) ref_chigh
FROM b
), res AS (
SELECT A.*, rt.*, ROW_NUMBER() OVER(PARTITION BY patient_nr ORDER BY ref_age DESC) AS rn
FROM A
LEFT JOIN refTable rt ON (rt.ref_age_cd = 'D' AND a.age_days > rt.ref_age)
OR (rt.ref_age_cd = 'M' AND a.age_months > rt.ref_age)
OR (rt.ref_age_cd = 'Y' AND a.age_years > rt.ref_age)
)
SELECT *
FROM res
WHERE rn = 1