【问题标题】:Logical lock in WHERE clauseWHERE 子句中的逻辑锁
【发布时间】:2018-02-07 21:12:48
【问题描述】:

由于 FUNCCODE 在 POSCODE 和 DEVCODE 之间共享,因此我不能同时调用两者来消除空值以将数据插入到名为 JOINT 的单独表中。 POSCODE 和 DEVCODE 是 FK。我知道必须有一种更简单的方法来做到这一点。在过去的两周里,我试图制定一个解决方案......感觉就像我不明白要完成这项工作的一件事。任何建议表示赞赏。

表设置

FUNCCODE | POSCODE | DEVCODE

    11        1       NULL
    12       NULL      1
    13        2       NULL 
    14       NULL      2

该表需要重新排列,然后插入到一个名为 JOINT 的单独表中,该表设置为:

POSCODE | POSFUNCCODE |DEVCODE | DEVFUNCCODE

   1          11          1         12
   2          13          2         14

我的一些尝试 XD

每个连接只创建我需要的 2 列

SELECT 
    dbo.POSITION.POSCODE AS POSCODE, 
    dbo.FUNC.FUNCCODE AS POSFUNCCODE
FROM FUNC
INNER JOIN POSITION ON dbo.POSITION.POSCODE = dbo.FUNC.POSCODE 

UNION ALL

SELECT 
    dbo.DEVICE.DEVCODE AS DEVCODE,
    dbo.FUNC.FUNCCODE AS DEVFUNCCODE
FROM FUNC
INNER JOIN DEVICE ON dbo.DEVICE.DEVCODE = dbo.FUNC.DEVCODE 
ORDER BY 1;

只插入最后一行的值

DECLARE @DATE DATETIME = GETDATE()

DECLARE @PC INT;

SELECT @PC = POSCODE 
FROM func
WHERE poscode != 0 
ORDER BY 1;

DECLARE @FCP INT;

SELECT @FCP = FUNCCODE 
FROM FUNC
WHERE POSCODE != 0 
ORDER BY 1;

DECLARE @DC INT;

SELECT @DC = devcode 
FROM func
WHERE devcode != 0
ORDER BY 1;

DECLARE @FCD INT

SELECT @FCD = FUNCCODE 
FROM FUNC
WHERE DEVCODE != 0
ORDER BY 1

INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME,             
JOINTSTATUS)
VALUES (@PC, @FCP, @DC, @FCD, @DATE, 1)

【问题讨论】:

  • 那么如果POSCODE=1 那么DEVCODE=1 他们应该如何匹配?
  • 另外,SQL 的版本和风格是什么?
  • @Shawn MS SQL Express 2012,是的!
  • 根据您对@user4219031 的回答的评论,您能否更新原始问题中的架构以包括 POSITION、DEVICE 和 FUNC 表以及它们之间的关系?原来的帖子听起来好像都在一张桌子上。这开始成为一个 XY 问题。 :-S xyproblem.info
  • 另外,您是否要从POSITIONDEVICE 中获取另一列?如果您只需要POSCODEDEVCODE,则上述查询不需要JOIN;这些列已经在FUNC 中。直接查询该表即可。我认为我们需要更多关于您要解决的完整问题的数据。

标签: sql-server tsql join union sql-insert


【解决方案1】:

如果我对您的问题的理解是正确的,我认为以下查询将是一个解决方案。

INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
POSTCODE,
    DEVCODE,
    MAX(CASE
    WHEN POSCODE IS NOT NULL THEN FUNCCODE
    ELSE NULL
END) POSFUNCCODE,
MAX(CASE
    WHEN DEVCODE IS NOT NULL THEN FUNCCODE
    ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY POSTCODE,DEVCODE

更好理解后的第二个版本

INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
   t1.POSTCODE,
   t2.DEVCODE,
   t1.POSFUNCCODE,
   t2.DEVFUNCCODE
(SELECT
  POSTCODE,
  MAX(CASE
        WHEN POSCODE IS NOT NULL THEN FUNCCODE
        ELSE NULL
    END) POSFUNCCODE
FROM FUNC
GROUP BY POSTCODE) t1
INNER JOIN
(SELECT
  DEVCODE,
  MAX(CASE
        WHEN DEVCODE IS NOT NULL THEN FUNCCODE
        ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY DEVCODE) t2
ON t1.POSTCODE = t2.DEVCODE

【讨论】:

  • 感谢您的洞察!这确实将 POSCODE 与其 FUNCCODE 对齐,并将 DEVCODE 与其 FUNCCODE 对齐,但插入是由组错开的,留下大块 NULL 而不是将它们全部插入一行。这就是我所说的逻辑锁。它只允许插入一个条件,因为 FUNCCODE 在其他两列之间共享。我尝试消除 else 子句,但分组仍然存在。也许有一种方法可以在插入一整列后执行更新。当我找到一个解决方案时,我会发布我的解决方案。因为我会找到一个 XD
  • @Brandoncbaldwin - POSTCODE 和 DEVCODE 之间是否存在会产生一条记录的关系?好像一条记录具有相同的 POSCODE 和 DEVCODE?
  • @Brandoncbaldwin。如果有,如果答案中的查询,我添加了第二个版本
  • 试图解决我脑海中的表危机,因为POSCODE属于POSITION表,DEVCODE属于DEVICE表,FUNCCODE属于FUNC表。 FUNCCODE 需要与其正确的 POSCODE 和 DEVCODE 匹配,然后插入。不过,我觉得突破了!
  • 反对所有更好的判断,我创建了一个插入正确值的循环。不过仍在研究这个逻辑!
【解决方案2】:

根据我更好的判断,我创建了一个循环来插入正确的值....我知道这不是解决此问题的正确方法,请原谅我,因为我在 SQL 方面的经验很少。但这更正了客户端程序中的接口问题。向@user4219031 寻求指导!

DECLARE @DATE DATETIME = GETDATE()

DECLARE @PC INT = 0;

DECLARE  @FCP INT = 12;

DECLARE @DC INT = 0;

DECLARE @FCD INT = 13

WHILE ( @PC < 739 )
BEGIN 
    INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME, JOINTSTATUS)
   VALUES( @PC, @FCP, @DC, @FCD, @DATE, 1)
    SET @PC = @PC + 1
    SET @FCP = @FCP +2 
    SET @DC = @DC + 1
    SET @FCD = @FCD + 2

END 

【讨论】:

  • 确保考虑边缘情况。此外,这依赖于幻数(@PC+1 等)。当您迁移到实时系统时,这可能会导致各种问题。这些数字在测试环境之外很快就会变得不准确。
【解决方案3】:

编辑:我将查询更改为考虑 NULL POSCODEDEVCODE

SQL Fiddle

MS SQL Server 2017 架构设置

CREATE TABLE t ( FUNCCODE int, POSCODE int,  DEVCODE int ) ;

INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES 
    ( 11, 1, NULL )
  , ( 12, NULL, 1 )
  , ( 13, 2, NULL )
  , ( 14, NULL, 2 )
  , ( 42, NULL, 1 )
  , ( 77, NULL, 7 )
  , ( 88, NULL, 8 )
  , ( 99, 9, NULL )
; 

创建新表并插入记录

CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;

INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
  , t1.FUNCCODE AS pos_FUNCODE
  , t2.DEVCODE
  , t2.FUNCCODE AS dev_FUNCCODE 
FROM t t1
FULL OUTER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL OR t2.DEVCODE IS NOT NULL

;

新表中有什么?

SELECT * FROM ti 

Results

| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
|       1 |           11 |       1 |           12 |
|       1 |           11 |       1 |           42 |
|       2 |           13 |       2 |           14 |
|       9 |           99 |  (null) |       (null) |
|  (null) |       (null) |       7 |           77 |
|  (null) |       (null) |       8 |           88 |

==========原创==========

SQL Fiddle

MS SQL Server 2017 架构设置

CREATE TABLE t ( FUNCCODE int, POSCODE int,  DEVCODE int ) ;

INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES 
    ( 11, 1, NULL )
  , ( 12, NULL, 1 )
  , ( 13, 2, NULL )
  , ( 14, NULL, 2 )
; 

创建新表并插入记录

CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;

INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
  , t1.FUNCCODE AS pos_FUNCODE
  , t2.DEVCODE
  , t2.FUNCCODE AS dev_FUNCCODE 
FROM t t1
INNER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL
;

新表中有什么?

SELECT * FROM ti 

Results

| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
|       1 |           11 |       1 |           12 |
|       2 |           13 |       2 |           14 |

【讨论】:

  • 我创建了另一个示例来说明 OP 的意图,即为 xxxCODE 使用 3 个单独的表。 sqlfiddle.com/#!18/c589e/1 FUNC 表。没有JOIN 其他两个必要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 2014-03-21
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多