我正在创建一个函数,可以根据可用信息从用户帐户记录中轻松检索客户端名称。除了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;
你的文字问题的答案是否定的 - 存储过程或存储函数的参数不能是对行对象的引用。它们必须是标量数据类型,例如用于定义表中列的数据类型。
您可以改为定义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语句。重写视图定义非常快。
SQL不是文本操作的好语言。 SQL是一种用于存储和检索数据的好语言。
在应用程序代码中保留“业务逻辑”。也就是说,有一层代码(使用您正在使用的语言)执行Account_Name操作。
“客户端”可以使用行引用或任何有意义的方式调用Layer。设计API以保持其清洁。然后,Layer执行任何需要的脏工作来实现这样的功能。它甚至可能不得不跑到多个桌子来收集碎片。
例如,今天你在同一张表中有email
。如果明天你把它放在其他地方,那么改变图层做两个SELECTs
或(更好)一个SELECT
与JOIN
。