【问题标题】:Using variable for fieldname in postgresql在 postgresql 中使用变量作为字段名
【发布时间】:2021-05-09 10:15:19
【问题描述】:

我有一个函数,我希望能够在 Postgres 函数中使用文本变量作为字段名称。

DECLARE
_currentEmployee text;
_myCount integer;

BEGIN

FOR _record IN 
        SELECT ...
LOOP

        _currentEmployee = _record.name
        _myCount = (SELECT count(*) FROM tblTraining
                    WHERE tblTraining._currentEmployee = 4);

        If _mycount = 0 ...

END LOOP;

基本上,检查每个员工的培训记录是例行公事。表架构有明显的问题,因为员工都作为列输入到培训表中,而不是每行中的规范化 ID,但我必须使用这里的内容。

每当我运行该函数时,它都会按字面意思对待_currentEmployee,而不是用字段名称替换它并正确处理。我得到了错误:

_currentlEmployee is not a field of tblTraining

建议?

【问题讨论】:

  • 请始终提供完整函数定义,包括标题和语言定义(即使它当前不工作)。还有你的 Postgres 版本。

标签: function postgresql plpgsql dynamic-sql


【解决方案1】:

一般情况下,SQL 中不允许使用参数化标识符。

在 PL/pgSQL 函数中,这可以通过 EXECUTE 执行的动态 SQL 字符串来规避。警惕 SQL 注入。列名必须像用户输入一样对待。

DECLARE
   _rec record;
   _ct  integer;
BEGIN

FOR _rec IN 
   SELECT ...
LOOP
   EXECUTE format(
     'SELECT count(*) FROM tblTraining
      WHERE  tbltraining.%I = 4', _rec.name);  -- %I avoids SQL injection
   INTO _ct;

   IF _ct = 0 THEN ...

END LOOP;

format()%I 将字符串清理为有效标识符。防止语法错误和 SQL 注入。请注意,在 Postgres 中,未加引号的标识符总是小写。如果您的真实列名是小写的,则必须在此处提供小写版本。
切勿在 Postgres 中使用 CaMeL-case 标识符以避免所有相关问题。

尝试搜索 + 以获取更多示例:

【讨论】:

  • 非常感谢您的建议! SELECT INTO 是我没有考虑过的缺失部分。我也很欣赏关于避免 SQL 注入的意见。我将使用 %I 对 format() 进行更多研究,以便在使用前清楚地理解它。
【解决方案2】:

EXECUTE 应该是你在这个任务上的朋友。

http://www.postgresql.org/docs/9.3/static/plpgsql-statements.html

EXECUTE 'SELECT count(*) FROM tblTraining WHERE '
    || _currentEmployee
    || ' = 4'
   INTO _myCount;

【讨论】:

    猜你喜欢
    • 2022-12-31
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多