问题:
我正在PostgreSQL 9.0中工作,我很难搞清楚如何处理你想要返回特定行的特定列值以便在CASE WHEN THEN语句中使用的情况。
我想基本上进入并设置表A的值:someRow的someColumn值,等于表B的值:行X的列A值,给定行X列B的值。(更多细节见“Backround信息“如果需要了解问题”
这就是我想做的事(但不知道如何):
Update tableA
Set someColumn
CASE WHEN given_info_column = 'tableB: row X's column B value'
THEN (here I want to return row X's column A value, finding row X using the given column B value)
ELSE someColumn END
背景资料:(可选,澄清)
想象一下,在现有数据库中存在一个用户活动表和一个设备表,其中已经存在的活动执行了您正在使用的代码库中存在的字符串:(例如)
User_Activity:
id (int) | user_name (string) | activity_preformed (string) | category (string)
---------|-----------------------|----------------------------------------|------------------
1 | Joe Martinez | checked out iphone: iphone2 | dvc_activity
2 | Jon Shmoe | uploads video from device: (id: 12345) | dvc_activity
3 | Larry David | goes to the bathroom |other_activity
Device:
seq (int)| device_name (string) | device_srl_num (int) | device_status (string)|
---------+-----------------------+----------------------+-----------------------+
1 | iphone1 | 12344 | available
2 | iphone2 | 12345 | checked out
3 | android1 | 23456 | available
你老板的任务是创建一个报告,显示一个包含所有设备活动的表,如下所示:
Device Activity Report
(int) (int) (string) (string) (string) (int) (string)
act_seq |usr_id | usr_name | act_performed | dvc_name | dvc_srl_num | dvc_status
---------+-------+--------------+---------------------------------------+-----------+-------------+------------
1 |1 | Joe Martinez | Checked out iphone: iphone2 | iphone2 | 12345 | checked out
2 |2 | John Shmoe | uploads video from device: (id: 12345)| android1 | 23456 | available
出于此问题的目的,必须通过向名为dvc_seq的用户活动表添加新列来完成此操作,该列将是设备表的外键。您将通过从用户活动表中查询并加入User_Activity(dvc_seq)= Device(seq)
中的两个来创建临时表。这很好,适用于User_Activity表中的新条目,该表将记录链接到关联设备的
问题是您需要进入并填写User_Activity表中新dvc_seq列的值,以获取与设备相关的所有先前条目。由于之前的程序员决定使用序列号指定activity_performed列中的哪个设备以及其他时间的设备名称,这会产生一个有趣的问题,您需要从设备派生相关的设备序列号,并给出其名称或序列号。
再一次,我想做什么:(使用这个例子)
UPDATE User_Activity
SET dvc_seq
CASE WHEN activity_performed LIKE 'checked out iphone:%'
THEN (seq column of Device table)
WHERE (SELECT 1 FROM Device WHERE device_name = (substring in place of the %))
ELSE dvc_seq (I think this would be null since there would be nothing here yet)
END
你们任何人都可以帮助我实现这个目标吗?提前感谢所有回复和建议!
答案 0 :(得分:2)
当activity_performed中包含序列号或名称时,下面的查询使用update-join来更新序列号
UPDATE UserActivity
SET a.dvc_seq = b.seq
FROM UserActivity AS a
JOIN devices b
ON UserActivity.activity_performed LIKE '%from device: (id: ' || b.serial_num || '%'
OR UserActivity.activity_performed LIKE '%: ' || b.name || '%'
答案 1 :(得分:1)
关于如何根据@FuzzyTree给出的正确答案加速此代码的另一个更新(这仅适用于具有标准长度的序列号,而不适用于可能很多的设备名称不同的尺寸)
由于连接中使用了LIKE,因此对于大型数据库,查询运行速度非常慢。一个更好的解决方案是利用postgres substring()
和position()
函数,并将序列号上的表连接起来,如下所示:
UPDATE UserActivity
SET a.dvc_seq = b.seq
FROM UserActivity AS a
JOIN devices b
ON b.serial_num =
substring(activity_performed from position('%from device: (id: ' in activity_performed)+(length of the string before the plus so that position returns the start position for the serial number)) for (lengthOfSerialNumberHere))
WHERE UserActivity.activity_performed LIKE '%from device: (id: ' || b.serial_num || '%';`
答案 2 :(得分:0)
在postgresql中,您无法执行复杂的CASE表达式,如
CASE WHEN activity_performed LIKE 'checked out iphone:%'
仅
CASE WHEN 1, 2
您可以做的最好的事情是创建一个功能
UPDATE User_Activity
SET dvc_seq = getDeviceID(User_Activity.activity_preformed);
在这里你可以做到IF,CASE更容易
CREATE OR REPLACE FUNCTION getDeviceID(activity text)
RETURNS integer AS
$BODY$
DECLARE
device_name text;
device_id integer;
BEGIN
-- parse the string activity
/* this part is pseudo code
set device_id;
IF (device_id is null)
set device_name;
search for device_id using device_name;
set device_id;
*/
RETURN device_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION get_box(text)
OWNER TO postgres;