Firebird 和 SQL 服务器删除组中最高的行

Firebird and SQL Server delete highest rows in groups

我需要从以下 tables:

中删除第 3 条和更大的记录,按产品、类型和显示顺序排序

Stockist table:

CREATE TABLE INVENTORYWEBSTOCKISTS
(
  STOCKISTID     NUMERIC(10,0) NOT NULL,
  PRODUCTID  NUMERIC(10,0) NOT NULL,
  DISPLAYORDER   NUMERIC(10,0),
  CUSTOMERID     NUMERIC(10,0),
CONSTRAINT PK_INVENTORYWEBSTOCKISTS PRIMARY KEY (STOCKISTID)
);

STOCKISTID 是 table 的唯一 autoinc 列,可用作 ID。 PRODUCTIDCUSTOMERID 都引用了其他 table。

Customer table:

CREATE TABLE CUSTOMERS 
(
  CUSTOMERID     NUMERIC(10,0) NOT NULL,
  WEBSTOCKISTSTOCKISTTYPE    VARCHAR(100),
CONSTRAINT PK_CUSTOMERS PRIMARY KEY (CUSTOMERID)
);

Customers table 有记录:

insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (1, 'Reseller');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (2, 'Reseller');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (3, 'Reseller');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (4, 'Installer');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (5, 'Installer');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (6, 'Installer');
insert into CUSTOMERS (CUSTOMERID, WEBSTOCKISTSTOCKISTTYPE) values (7, 'Installer');

Stockist table 有记录:

insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (1, 1, -100, 1);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (2, 1, -101, 2);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (3, 1, -102, 3);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (4, 1, -103, 4);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (5, 1, -104, 5);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (6, 1, -105, 6);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (7, 1, -106, 7);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (10, 2, -107, 3);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (13, 2, -108, 6);
insert into INVENTORYWEBSTOCKISTS (STOCKISTID, PRODUCTID, DISPLAYORDER, CUSTOMERID) values (14, 2, -109, 7);

综合结果:

select
    INVENTORYWEBSTOCKISTS.STOCKISTID,
    INVENTORYWEBSTOCKISTS.PRODUCTID,
    INVENTORYWEBSTOCKISTS.DISPLAYORDER,
    CUSTOMERS.WEBSTOCKISTSTOCKISTTYPE
from
    INVENTORYWEBSTOCKISTS
left join
    CUSTOMERS on CUSTOMERS.CUSTOMERID = INVENTORYWEBSTOCKISTS.CUSTOMERID
order by
    INVENTORYWEBSTOCKISTS.PRODUCTID,
    CUSTOMERS.WEBSTOCKISTSTOCKISTTYPE,
    INVENTORYWEBSTOCKISTS.DISPLAYORDER

输出:

STOCKISTID, PRODUCTID, DISPLAYORDER, WEBSTOCKISTSTOCKISTTYPE
7,  1, -106, Installer
6,  1, -105, Installer
5,  1, -104, Installer
4,  1, -103, Installer
3,  1, -102, Reseller
2,  1, -101, Reseller
1,  1, -100, Reseller
14, 2, -109, Installer
13, 2, -108, Installer
10, 2, -107, Reseller

我需要删除按显示顺序排序的每个 product/stockist 类型组的第 3 条及以上记录,因此预计它会删除第 5、4 和 1 行。

我已经从这里和网络上尝试了很多不同的查询,我找不到任何可以分组和排序的删除以及在 MS SQL 和 Firebird 1.5 上工作的任何东西。

SQL Fiddle 试验:http://sqlfiddle.com/#!3/7101de/1

所以删除后,table 应该是这样的:

输出:

STOCKISTID, PRODUCTID, DISPLAYORDER, WEBSTOCKISTSTOCKISTTYPE
7,  1, -106, Installer
6,  1, -105, Installer
3,  1, -102, Reseller
2,  1, -101, Reseller
14, 2, -109, Installer
13, 2, -108, Installer
10, 2, -107, Reseller

删除应该作为一个查询执行,所以我可以将它传递给服务器。

*** 编辑:

也许为了简化,如果我可以执行一个 select 命令来删除 return 的 STOCKISTID,然后我可以单独执行删除命令。

*** 编辑 2:

作为测试,我将库存商类型字段添加到 INVENTORYWEBSTOCKISTS table,并且可以运行 这个查询:

SELECT INVENTORYWEBSTOCKISTS.STOCKISTID
FROM   INVENTORYWEBSTOCKISTS IWS1
WHERE
(SELECT COUNT(*)
FROM INVENTORYWEBSTOCKISTS  IWS2
WHERE IWS2.PRODUCTID = IWS1.PRODUCTID
AND IWS2.STOCKISTTYPE = IWS1.STOCKISTTYPE
AND IWS2.DISPLAYORDER <= IWS1.DISPLAYORDER) > 2

和 return 正确的字段(即应该删除的字段)。这是基于之前在 SO 上提出的问题。

当我尝试在 CUSTOMER table 中 link 作为查询时,它会给出不同的结果,更少的行。也许有人可以提供帮助?

试试这个,我已经使用 ROW_NUMBER 消除了你的情况(根据我从你的问题中了解到的情况)

    ;WITH CTE AS(
    SELECT ROW_NUMBER()OVER(PARTITION BY PRODUCTID,WEBSTOCKISTSTOCKISTTYPE
                          ORDER BY (SELECT 1) )SNO, INVENTORYWEBSTOCKISTS.*,
                         CUSTOMERS.WEBSTOCKISTSTOCKISTTYPE FROM
    INVENTORYWEBSTOCKISTS
    LEFT JOIN
      CUSTOMERS ON INVENTORYWEBSTOCKISTS.CUSTOMERID = CUSTOMERS.CUSTOMERID
     )

     SELECT * FROM CTE WHERE SNO <3 

编辑:来自您的评论:

    ;WITH CTE AS(
    SELECT ROW_NUMBER()OVER(PARTITION BY PRODUCTID,WEBSTOCKISTSTOCKISTTYPE
        ORDER BY (SELECT DISPLAYORDER) )SNO, INVENTORYWEBSTOCKISTS.*,
        CUSTOMERS.WEBSTOCKISTSTOCKISTTYPE FROM
    INVENTORYWEBSTOCKISTS
    LEFT JOIN
    CUSTOMERS ON INVENTORYWEBSTOCKISTS.CUSTOMERID = CUSTOMERS.CUSTOMERID
    )
    SELECT STOCKISTID FROM CTE WHERE SNO>2

如果是CTE的问题

    DELETE FROM INVENTORYWEBSTOCKISTS WHERE STOCKISTID IN ( 

    SELECT STOCKISTID FROM (
    SELECT ROW_NUMBER()OVER(PARTITION BY PRODUCTID,WEBSTOCKISTSTOCKISTTYPE
                ORDER BY (SELECT DISPLAYORDER) )SNO, INVENTORYWEBSTOCKISTS.*,
                CUSTOMERS.WEBSTOCKISTSTOCKISTTYPE FROM
            INVENTORYWEBSTOCKISTS
            LEFT JOIN
            CUSTOMERS ON INVENTORYWEBSTOCKISTS.CUSTOMERID = CUSTOMERS.CUSTOMERID
            ) AS A WHERE SNO>2
            )