postgresql 具有NULL值的两个表达式结果之间的差异

tvz2xvvm  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(2)|浏览(133)

我很好奇为什么下面的两个表达式有不同的结果--一个是NULL,另一个是TRUE

postgres=# select array[1,null]=array[1,null];
 ?column? 
----------
 t
(1 row)

postgres=# select (1,null)=(1,null);
 ?column? 
----------
 
(1 row)

字符串
这是什么原因呢?在你的回答中,你能不能链接到Postgres的文档或一些SQL参考,在那里它说了与内部的NULL值进行比较时,行和列表类型的行为?

qq24tv8q

qq24tv8q1#

数组 * 包含 * null在相同的位置(S)比较相等,如果所有其他都是平等的。比较时,只有实际的null值(包括数组值 * 作为一个整体 *)返回null

SELECT null::int[] = null::int[];  --> null

字符串
对于行比较,Postgres遵循SQL标准。The manual on Row and Array Comparisons:
涉及数组子表达式的形式是PostgreSQL扩展;其余的都是SQL兼容的。

  • 行构造函数比较手册 *:

=<>的工作方式与其他情况略有不同。如果两行的所有对应成员都非空且相等,则认为它们相等;如果任何对应的成员非空且不相等,则行是不相等的;否则行比较的结果未知(null)

大胆强调我的。所以行比较与数组比较有细微的不同。如果行值中的嵌套null值比较起来相等(如数组中),则使用IS NOT DISTINCT FROM而不是=

SELECT (1,null) IS NOT DISTINCT FROM (1,null);  --> true

wsxa1bj1

wsxa1bj12#

来源:https://git.postgresql.org/cgit/postgresql.git/tree/src/backend/utils/adt/arrayfuncs.c#n3760
解释第一个查询select array[1,null]=array[1,null];
3784-3787比较两个数组基本元素数据类型。
3790-3793两个数组维度/边界信息检查。
3796-3813检查天气数组基类型是否具有相等功能。某些数据类型没有相等函数。3825-3828为两个阵列建立迭代。
3838-3853,对于数组中的每个基本元素,为Datum或null。因此迭代并复制datum或null(datum(非null)或null中一个元素)到变量(it 1,isnull 1,it 2,isnull 2)。
你在第3845行和第3848行回答。
src/backend/utils/adt/arrayfuncs.c

3760: Datum
3761: array_eq(PG_FUNCTION_ARGS)
3762: {
3763:   LOCAL_FCINFO(locfcinfo, 2);
3764:   AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3765:   AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3766:   Oid         collation = PG_GET_COLLATION();
3767:   int         ndims1 = AARR_NDIM(array1);
3768:   int         ndims2 = AARR_NDIM(array2);
3769:   int        *dims1 = AARR_DIMS(array1);
3770:   int        *dims2 = AARR_DIMS(array2);
3771:   int        *lbs1 = AARR_LBOUND(array1);
3772:   int        *lbs2 = AARR_LBOUND(array2);
3773:   Oid         element_type = AARR_ELEMTYPE(array1);
3774:   bool        result = true;
3775:   int         nitems;
3776:   TypeCacheEntry *typentry;
3777:   int         typlen;
3778:   bool        typbyval;
3779:   char        typalign;
3780:   array_iter  it1;
3781:   array_iter  it2;
3782:   int         i;
3783: 
3784:   if (element_type != AARR_ELEMTYPE(array2))
3785:       ereport(ERROR,
3786:               (errcode(ERRCODE_DATATYPE_MISMATCH),
3787:                errmsg("cannot compare arrays of different element types")));
3788: 
3789:   /* fast path if the arrays do not have the same dimensionality */
3790:   if (ndims1 != ndims2 ||
3791:       memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
3792:       memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
3793:       result = false;
3794:   else
3795:   {
3796:       /*
3797:        * We arrange to look up the equality function only once per series of
3798:        * calls, assuming the element type doesn't change underneath us.  The
3799:        * typcache is used so that we have no memory leakage when being used
3800:        * as an index support function.
3801:        */
3802:       typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
3803:       if (typentry == NULL ||
3804:           typentry->type_id != element_type)
3805:       {
3806:           typentry = lookup_type_cache(element_type,
3807:                                        TYPECACHE_EQ_OPR_FINFO);
3808:           if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
3809:               ereport(ERROR,
3810:                       (errcode(ERRCODE_UNDEFINED_FUNCTION),
3811:                        errmsg("could not identify an equality operator for type %s",
3812:                               format_type_be(element_type))));
3813:           fcinfo->flinfo->fn_extra = (void *) typentry;
3814:       }
3815:       typlen = typentry->typlen;
3816:       typbyval = typentry->typbyval;
3817:       typalign = typentry->typalign;
3818: 
3819:       /*
3820:        * apply the operator to each pair of array elements.
3821:        */
3822:       InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
3823:                                collation, NULL, NULL);
3824: 
3825:       /* Loop over source data */
3826:       nitems = ArrayGetNItems(ndims1, dims1);
3827:       array_iter_setup(&it1, array1);
3828:       array_iter_setup(&it2, array2);
3829: 
3830:       for (i = 0; i < nitems; i++)
3831:       {
3832:           Datum       elt1;
3833:           Datum       elt2;
3834:           bool        isnull1;
3835:           bool        isnull2;
3836:           bool        oprresult;
3837: 
3838:           /* Get elements, checking for NULL */
3839:           elt1 = array_iter_next(&it1, &isnull1, i,
3840:                                  typlen, typbyval, typalign);
3841:           elt2 = array_iter_next(&it2, &isnull2, i,
3842:                                  typlen, typbyval, typalign);
3843: 
3844:           /*
3845:            * We consider two NULLs equal; NULL and not-NULL are unequal.
3846:            */
3847:           if (isnull1 && isnull2)
3848:               continue;
3849:           if (isnull1 || isnull2)
3850:           {
3851:               result = false;
3852:               break;
3853:           }
3854: 
3855:           /*
3856:            * Apply the operator to the element pair; treat NULL as false
3857:            */
3858:           locfcinfo->args[0].value = elt1;
3859:           locfcinfo->args[0].isnull = false;
3860:           locfcinfo->args[1].value = elt2;
3861:           locfcinfo->args[1].isnull = false;
3862:           locfcinfo->isnull = false;
3863:           oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
3864:           if (locfcinfo->isnull || !oprresult)
3865:           {
3866:               result = false;
3867:               break;
3868:           }
3869:       }
3870:   }
3871: 
3872:   /* Avoid leaking memory when handed toasted input. */
3873:   AARR_FREE_IF_COPY(array1, 0);
3874:   AARR_FREE_IF_COPY(array2, 1);
3875: 
3876:   PG_RETURN_BOOL(result);
3877: }
3878:

字符串

相关问题