我正在创建一个函数,可以根据可用信息从用户帐户记录中轻松检索客户端名称。除id
以外的所有帐户字段都是可选的,可能是空白的,因此这会连续检查各个标识列,直到找到一个,并返回id
作为最后一个结果。
CREATE FUNCTION ACCOUNT_NAME(
fname varchar(50),
lname varchar(50),
company varchar(50),
email varchar(50),
id int(10) unsigned
)
RETURNS VARCHAR(100) DETERMINISTIC CONTAINS SQL SQL SECURITY INVOKER
RETURN
IF( TRIM(CONCAT(fname, ' ', lname)) <> '',
TRIM(CONCAT(fname, ' ', lname)),
IF( company <> '',
company,
IF(email <> '', email, id)
)
)
;
这很好用,但我需要将每一列单独传递给函数,即:
SELECT ACCOUNT_NAME(
a.first_name,
a.last_name,
a.company,
a.email,
a.id
) AS client_name
FROM accounts AS a WHERE 1;
这不仅繁琐,将来修改或扩展此功能将非常困难,可能需要查找和更新每个调用以及定义本身。
是否可以将对整个行结果的引用作为输入参数传递?理想情况下,我想做这样的事情:
CREATE FUNCTION ACCOUNT_NAME(row result)
RETURNS VARCHAR(100) DETERMINISTIC CONTAINS SQL SQL SECURITY INVOKER
RETURN
IF( TRIM(CONCAT(row.first_name, ' ', row.last_name)) <> '',
TRIM(CONCAT(row.first_name, ' ', row.last_name)),
IF( row.company <> '',
row.company,
IF(row.email <> '', row.email, row.id)
)
)
;
SELECT ACCOUNT_NAME(a.*) AS client_name
FROM accounts AS a WHERE 1;
答案 0 :(得分:1)
您的文字问题的答案是否定的 - 存储过程或存储函数的参数不能是对行对象的引用。它们必须是标量数据类型,例如用于在表中定义列的数据类型。
您可以改为定义VIEW:
CREATE OR REPLACE VIEW accounts_view (id, client_name) AS
SELECT id, COALESCE(
NULLIF(CONCAT(fname, ' ', lname), ' '),
NULLIF(company, ''),
NULLIF(email, ''),
id) AS client_name
FROM accounts;
然后您可以更简单地查询:
SELECT client_name
FROM accounts_view;
如果您想要更改格式化client_name
的方式,那么只需使用另一个CREATE OR REPLACE VIEW语句即可。重写视图定义非常快。
答案 1 :(得分:0)
SQL不是文本操作的好语言。 SQL是存储和检索数据的好语言。
在应用程序代码中保留“业务逻辑”。也就是说,有一层代码(使用您正在使用的语言)执行Account_Name操作。
“客户端”可以使用行引用或任何有意义的方式调用Layer。设计API以保持其清洁。然后,Layer执行任何需要的脏工作来实现这样的功能。它甚至可能不得不跑到多个桌子上来收集碎片。
例如,今天您在同一个表中有email
。如果明天你将它放在其他地方,那么将图层更改为使用SELECTs
执行两个SELECT
或(更好)一个JOIN
。