SQL 视图中的双列

Posted

技术标签:

【中文标题】SQL 视图中的双列【英文标题】:Double columns in a SQL View 【发布时间】:2011-05-24 09:39:17 【问题描述】:

我们有一个旧接口插入到表 T1 中,其值为 "BODY_TEXT" (varcharmax)"BODY_BIN"(varbinarymax)。 它当前只插入其中一列,而将另一列保留为 NULL。 现在我们实现了一个新接口——表 T2,它只有 "BODY"(varbinarymax) 列。

我需要创建一个视图 V1 来代替 T1,意思是

CREATE VIEW V1 AS
SELECT 
T2.UNIQUE_ID AS UNIQUE_ID,

等等……

现在我不知道如何处理T2.BODY 列……我需要做类似的事情 T2.BODY AS (whatever is not null(BODY_BIN, BODY_TEXT))。它还必须支持 varcharmax 与 varbinarymax。 我尝试实现COALESCE,意思是T2.BODY AS COALESCE(BODY_BIN, BODY_TEXT),但它不起作用。 也没有

COALESCE(BODY_BIN, BODY_TEXT) AS BODY
T2.BODY AS BODY

再次 - 在旧表中,我们的 T1 有两列 - BODY_BIN 和 BODY_TEXT。用户插入了一个值,而将另一个留空,因为 body 要么是二进制的,要么是文本的,但不是两者兼而有之。新界面有一个表 T2,它只有一列 BODY (varbinarymax),我被要求删除表 T1 并创建一个同名的视图。意思是为了保持向后可比性,他们应该仍然能够执行“插入 T1 值 X,Y”(X 是 DATA_BIN 或 NULL,Y 是 DATA_TEXT 或 NULL),但内容(取自 X 或 Y)应该被翻译成 T2 表中的一列 - BODY。 我不知道如何把这个拉起来。

你能帮帮我吗?

谢谢,

尼莉

【问题讨论】:

我不确定我是否理解。 COALESCE(, ) 应该可以工作。 是的,但请注意方向不同——通常你“映射”表来查看,意思是 COALESCE(DATA_BIN, DATA_TEXT) AS T.BODY,但是我需要从视图中映射一个最大值,意思是 T2.BODY AS COALESCE(DATA_BIN, DATA_TEXT),或者类似的东西...... 我读对了吗:您想根据返回的数据类型更改列名吗? 没有托拜厄斯。在旧表中,我们有 T1 有两列 - BODY_BIN 和 BODY_TEXT。用户插入了一个值,而将另一个留空,因为 body 要么是二进制的,要么是文本的,但不是两者兼而有之。新界面有一个表 T2,它只有一列 BODY (varbinarymax),我被要求删除表 T1 并创建一个同名的视图。意思是为了保持向后可比性,他们仍然应该能够执行“插入 T1 值 X,Y”(X 是 DATA_BIN 或 NULL,Y 是 DATA_TEXT 或 NULL),但内容应转换为 T2 中的一列表 - 身体。 【参考方案1】:

varbinary 到 varchar(注意顺序)将隐式转换。所以这是可行的,因为 ISNULL 采用第一个数据类型

ISNULL(varchar, varbinary)

COALESCE 失败,因为它采用最高优先级数据类型(即 varbinary)。不允许隐式转换。 ISNULL(varbinary, varchar) 也会失败

你需要一个明确的 CAST

DECLARE @foo TABLE (ID int IDENTITY (1,1), charmax varchar(MAX) NULL, binmax varbinary(MAX) NULL)

INSERT @foo (charmax, binmax) VALUES ('text', NULL)
INSERT @foo (charmax, binmax) VALUES (NULL, 0x303131)
INSERT @foo (charmax, binmax) VALUES ('Moretext', NULL)
INSERT @foo (charmax, binmax) VALUES (NULL, 0x414243454647)

SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM @foo

SELECT COALESCE(binmax, CONVERT(varbinary(MAX), charmax))
FROM @foo

编辑:我现在明白了这个问题......也许

DECLARE @foo2 TABLE (ID int IDENTITY (1,1), BODY varbinary(MAX) NULL)

INSERT @foo2 (BODY) VALUES (CAST('text' AS varbinary(MAX)))
INSERT @foo2 (BODY) VALUES (0x303132)
INSERT @foo2 (BODY) VALUES (CAST('Moretext' AS varbinary(MAX)))
INSERT @foo2 (BODY) VALUES (0x414243454647)
SELECT
    BODY AS BODY_BIN,
    CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
    @foo2

Edit2:类似这样的东西(测试)保持相同的写入接口。通常,我只会维护一个读取接口,因此会造成混乱......

CREATE VIEW OldFoo
AS
SELECT
    ID,
    BODY AS BODY_BIN,
    CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
    newFoo
GO
CREATE TRIGGER ON OldFoo INSTEAD OF INSERT
AS
SET NOCOUNT ON
INSERT newFoo (BODY)
SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM INSERTED
GO

【讨论】:

我仍然不知道一个简单的演员表是否可行,我仍然落后了一步,因为我不知道如何将表 T2 中的一个“物理”列绑定到非 null-来自 V1 的两列中的值... @Nili:我已经给你证明它确实在我上面的脚本中工作 @gbn,仍然不完全是我的目标......我曾经有一个旧表 - DECLARE @foo TABLE (ID int IDENTITY (1,1), BODY_BIN varbinary(MAX) NULL, BODY_TEXT varchar(max)),现在我得到了一个新表 - foo2 - 就像你展示的一样。现在我的要求是删除表 foo,而是创建一个名为 foo 的视图。它应该支持老用户,这意味着支持插入 DATA_BIN 和 DATA_TEXT,但“幕后”将 JUST ONE VALUE 复制到全新的表 foo2...这是更好的解释吗? @Nili - 如果您想使用视图来查看INSERT 新数据,那么您需要有两个不同的字段,一个用于每种数据类型。另一种方法是有一个函数来执行一些逻辑来确定数据类型,但是将这种新方法塞进旧框架中的复杂程度近乎荒谬。 @Nili:所以用户仍然会尝试写入“foo”?【参考方案2】:

首先,这是一个糟糕的设计。加入varchar(max)varbinary(max) 字段是个坏主意,因为它们无法被索引。准备表扫描!

同一列的数据类型不一致,这是个问题。

试试:

CAST((COALESCE(BODY_BIN, BODY_TEXT)) as varchar(max))

【讨论】:

但我需要将 T2 值映射到非空值,这意味着我需要类似:T2.Body AS CAST((COALESCE(BODY_BIN, BODY_TEXT)) as varchar(max)),但是它不起作用...... @Nili: COALESCE(CAST(BODY_BIN AS varchar(max)), BODY_TEXT))?

以上是关于SQL 视图中的双列的主要内容,如果未能解决你的问题,请参考以下文章

sql中的视图怎么创建及使用呢!

怎样删除视图中的全部数据 用SQL语言编写。

用SQL代码创建一个视图,并查询视图中的字段

SQL VIEW(视图)

SQL VIEW(视图)

SQL中的存储过程,函数,视图有啥区别?