您如何 return 数据库中现有 table 中特定行的特定列值?

How do you return a specfic column value of a certain row in an existing table within a database?

问题:

我在 PostgreSQL 9.0 中工作,我很难弄清楚如何解决你想要 return 某行的特定列值用于 CASE WHEN 的情况然后声明。

我想基本上进去设置table的值 A:someRow的someColumn的值,等于table的值 B:行X的列A的值,给定行的值X 的 B 列。(如果需要了解问题,请参阅 "Backround Info" 中的更多详细信息)

这是我想做的(但不知道怎么做):

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

背景信息:(可选,用于说明)

假设在现有数据库中有一个用户 activity table 和一个设备 table,并且已经存在 activity 执行的字符串您正在使用的代码库:(例如)

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

你老板给你的任务是创建一份报告,显示一个 table 和所有设备 activity,如下所示:

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    

为了这个问题的目的,这必须通过向用户 activity table 添加一个名为 dvc_seq 的新列来完成,这将是设备的外键table。您将通过从用户 activity table 查询并加入两个 User_Activity (dvc_seq) = Device (seq)[=16 来创建临时 table =]

这很好,对于 User_Activity table 中的新条目非常有用,它将记录一个 dvc_seq 链接到相关设备 if activity 涉及设备。

问题是您需要在 User_Activity table 中的新 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

你们谁能帮我完成这个吗??预先感谢所有回复和建议!

在 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;

当序列号或名称包含在 activity_performed

中时,下面的查询使用更新连接来更新序列号
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 || '%'

只是关于如何根据@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 || '%';`