【发布时间】:2012-12-25 09:46:10
【问题描述】:
我有两张桌子:
DATA
DATA_ID | SAMPLE_ID | ASSAY_ID | SIGNAL
101 | 201 | 301 | 2.87964
102 | 201 | 302 | 7.64623
103 | 202 | 301 | 1.98473
...
还有SAMPLES:
SAMPLE_ID | SAMPLE_NAME | CATEGORY
201 | SAMP0001 | CAT A
202 | SAMP0002 | CAT B
203 | SAMP0003 | CAT A
...
SAMPLES 中有大约 20,000 行。对于每个样本,DATA 中大约有 40,000 行。每个ASSAY_ID 在DATA 中的每个样本仅出现一次。我需要获取SAMPLE 中的样本子集,并为DATA 中的每个信号值计算标准/z 分数值,并按ASSAY_ID 分组。我正在尝试创建一个将被重复调用的存储过程,它将接受单个 ASSAY_ID 值并为预定义样本子集中的所有样本返回 SAMPLE_ID 和 ZSCORE 对。
给定给定测定的一组样本信号值 (X = [3.21, 4.56, 1.12, ..]),在这种情况下,标准/z 分数计算为
(X[i] - median(X))/(K * MAD)
其中K 是比例因子,等于 1.4826,MAD 是调整后的中值偏差,等于:
median(|X[i]-median(X)|)
明白了吗?好 :) 现在,使用 SQL 查询执行此计算的最有效方法是什么?执行时间是关键,因为 DATA 中有近十亿行,并且几乎每个 SIGNAL 值都需要计算 z 分数。
这是迄今为止我能想到的最好的查询:
WITH BASE AS (
SELECT
S.SAMPLE_ID,
D.SIGNAL
FROM
DATA D
JOIN SAMPLES S
ON D.SAMPLE_ID = S.SAMPLE_ID
WHERE
S.CATEGORY IN ('CAT A', 'CAT B')
AND D.ASSAY_ID = 12345
AND S.SAMPLE_NAME NOT IN ('SAMP0003', 'SAMP0005', 'SAMP0008')
)
SELECT
A.SAMPLE_ID,
(A.SIGNAL-B.MED)/(1.4826*C.MAD) AS ZSCORE
FROM
BASE A,
(
SELECT MEDIAN(X.SIGNAL) AS MED
FROM BASE X
) B,
(
SELECT MEDIAN(ABS(Y.SIGNAL-YY.MED)) AS MAD
FROM BASE Y,
(SELECT MEDIAN(SIGNAL) AS MED FROM BASE) YY
) C
有没有更有效的方法来执行这个查询?
额外问题:我可以编写一个 SQL 查询,在一次执行中为每个 ASSAY_ID 执行此计算吗?
【问题讨论】:
标签: sql oracle plsql statistics