选择共同项目以进行2个或更多成员的价格比较

时间:2013-08-21 18:55:29

标签: sql-server tsql

我正在尝试根据成员根据购买日期支付的最近价格,对2个或更多成员进行购买价格比较。

我有四个表:成员,项目,UOM和事实

Member (membername varchar(50), memberkey int)

Items  (itemname varchar(50), itemkey int)

UOM    (uomname varchar(50), uomkey int)

Fact   (memberkey int, itemkey int, uomkey int, purchaseamount decimal(18,2), quantity int, purchasedate date)

我的用户界面允许选择两个或更多成员,以便比较每个人的价格。我的结果集必须包含至少有两个选定成员购买该项目并排除所有其他成员的项目。

我通过以下方式在临时表中设置我的成员列表:

    declare @MemberKeys as varchar(max)
    set @MemberKeys = '702,1382,1389,1390,1391,1392,1393,1394,1395,1396,1397,1401,1402,1404,1405,1406,1516,1844';
    create table #mk (memberName varchar(253), memberkey smallint)

    insert into #mk (memberName, memberkey)
    Select Rownbr + '.)  '  +  membername, memberkey from (
    SELECT
        cast(ROW_NUMBER() OVER(ORDER BY [MemberFacilityName] ASC) as varchar (10)) AS RowNbr
        ,k.value as memberkey
        ,m.memberName

    FROM 
        Member m
        INNER JOIN dbo.String_To_SmallInt_Table(@MemberKeys, ',') AS k
        ON m.Memberkey = k.value            
        ) X

然后我在查询fact,uom和item表时使用临时表进行过滤。

    select m.membername
    ,i.itemname
    ,u.uomname
    ,purchaseamount 
    ,quantity
    ,purchaseamount/quantity as price  
    from Fact f
    join #mk m
    on m.memberkey = f.memberkey
    join Item i
    on i.itemkey = f.itemkey
    join UOM u
    on u.uomkey= f.uomkey

现在我需要做以下事情,但需要一些指导来完成它。

1。)过滤掉至少两个选择成员未使用的项目。

2。)根据购买日期仅显示每位会员\ item \ uom的最新购买价格。

3。)命令结果集显示成员然后项目以便于比较(类似于下面的简化列表)。

Member   Item   Price
 mbr1       A   1.11
 mbr2       A   1.12
 mbr3       A   1.52
 mbr4       A   2.01
 mbr1       B   3.01
 mbr2       B   3.03
 mbr3       B   3.12
 mbr4       B   3.41
 mbr1       C   6.01
 mbr2       C   6.63
 mbr3       C   6.92
 mbr4       C   6.99

2 个答案:

答案 0 :(得分:1)

以下是我如何实现这个...告诉我我的逻辑是否合理:

/****Create Sample Data*****/

-->Member table
IF exists (SELECT 1 from dbo.sysobjects WHERE name = 'Member')
DROP TABLE Member
GO

CREATE TABLE Member (membername VARCHAR(50), memberkey INT)
GO 
INSERT INTO Member VALUES
('mbr1',702),
('mbr2',1382),
('mbr3',1389),
('mbr4',1390),
('mbr5',1391),
('mbr6',1392),
('mbr7',1393),
('mbr8',1394),
('mbr9',1395),
('mbr10',1396),
('mbr11',1397),
('mbr12',1401),
('mbr13',1402),
('mbr14',1404),
('mbr15',1405),
('mbr16',1406),
('mbr17',1516),
('mbr18',1111)-->Should NOT show up in query
GO

-->Items table
IF exists (SELECT 1 from dbo.sysobjects WHERE name = 'Items')
DROP TABLE Items
GO

CREATE TABLE Items  (itemname VARCHAR(50), itemkey INT)
GO
INSERT INTO Items VALUES
('A',1),
('B',2),
('C',3),
('D',4)

GO

-->UOM table   
IF exists (SELECT 1 from dbo.sysobjects WHERE name = 'UOM')
DROP TABLE UOM
GO
CREATE TABLE UOM    (uomname VARCHAR(50), uomkey INT)
GO

INSERT INTO UOM  VALUES ('QTY', 1)
GO

-->Fact table
IF exists (SELECT 1 from dbo.sysobjects WHERE name = 'Fact')
DROP TABLE Fact
GO
CREATE TABLE Fact   (memberkey INT, itemkey INT, uomkey INT, purchaseamount      decimal(18,2), quantity INT, purchasedate date)
GO

INSERT INTO Fact VALUES 
(702,  1, 1, 1.11, 2, '1/3/2012'),-->Should show up in query
(1382, 1, 1, 1.12, 3, '1/4/2013'),-->Should NOT show up in query
(1382, 1, 1, 1.14, 2, '7/5/2013'),-->Should show up in query
(1404, 1, 1, 1.21, 2, '1/7/2012'),-->Should show up in query
(1401, 2, 1, 3.01, 1, '4/2/2013'),-->Should NOT show up in query
(1111, 3, 1, 6.92, 1, '12/12/2012'),-->Should NOT show up in query
(702,  3, 1, 5.01, 2, '4/1/2011'),-->Should show up in query
(1401, 3, 1, 4.01, 1, '6/5/2012'),-->Should show up in query
(1397, 4, 1, 5.45, 1, '7/4/2013'),-->Should NOT show up in query
(1397, 4, 1, 5.22, 3, '3/15/2011')-->Should NOT show up in query
GO


/*****Code to get results*****/
BEGIN  

-->Members to Filter On
DECLARE @MemberKeys AS VARCHAR(max)
SET @MemberKeys = '702,1382,1389,1390,1391,1392,1393,1394,1395,1396,1397,1401,1402,1404,1405,1406,1516,1844';


-->Parse out comma delimited VALUES into a table variable
DECLARE @Member TABLE 
(
memberkey INT
)
DECLARE @spot SMALLINT, @str VARCHAR(max), @sql VARCHAR(max)  

WHILE @MemberKeys <> ''  
BEGIN  
    SET @spot = CHARINDEX(',', @MemberKeys)  
    IF @spot>0  
        BEGIN  
            SET @str = LEFT(@MemberKeys, @spot-1) 
            SET @MemberKeys = RIGHT(@MemberKeys, LEN(@MemberKeys)-@spot)  
        END  
    ELSE  
        BEGIN  
            SET @str = @MemberKeys 
            SET @MemberKeys = ''  
        END  
    INSERT INTO @Member VALUES(CONVERT(VARCHAR(100),@str))   
END  

END;


-->Display Results
WITH staged(memberkey, membername, itemname ,itemkey, uomname, uomkey, purchaseamount, quantity, price, purchasedate, noitems )  
AS
(
SELECT 
 m.memberkey
,m.membername
,i.itemname
,i.itemkey
,u.uomname
,u.uomkey
,f.purchaseamount 
,f.quantity
,f.purchaseamount/f.quantity as price  
,f.purchasedate
,COUNT(m.memberkey) OVER(PARTITION BY i.itemkey )-COUNT(m.memberkey) OVER(PARTITION BY  convert(VARCHAR,m.memberkey)+convert(VARCHAR,i.itemkey) ) as noitems
FROM 
Fact f
    JOIN Member m ON m.memberkey = f.memberkey
    JOIN Items i ON i.itemkey = f.itemkey
    JOIN UOM u ON u.uomkey= f.uomkey
 WHERE 
 EXISTS(SELECT 1 FROM @Member m2 WHERE m.memberkey=m2.memberkey)
 )
 SELECT
      memberkey, 
      membername, 
      itemname ,
          itemkey,
      uomname, 
          uomkey,
      sum(purchaseamount) as purchaseamount , 
      sum(quantity) as quantity , 
      sum(price) as price, 
      max(purchasedate) as purchasedate
 FROM
      staged st
 WHERE
          noitems>0
          and exists(
    select  memberkey, 
            itemkey ,
            uomkey,
            max(purchasedate) as maxdate 
           from staged st2 
                            where st.memberkey=st2.memberkey 
                            and st.itemkey=st2.itemkey 
                            and st.uomkey=st2.uomkey

            group by  
            memberkey, 
            itemkey ,
            uomkey
            having st.purchasedate=max(st2.purchasedate)
            )
 GROUP BY 
          memberkey 
     ,membername  
     ,itemname  
     ,uomname
         , itemkey 
     , uomkey 
 ORDER BY 
         itemname 
         ,memberkey;

答案 1 :(得分:0)

我能够自己解决这个问题,但会发表我自己的答案;也许它可以帮助其他有类似任务的人。

我能够通过引入第二个临时表来确定每个项目和成员的最新购买价格来完成这三项任务。然后将#mostrecentpurchase临时表加入基表,可以进行有效的成员价格比较。

要将结果集限制为只有两个或多个所选成员记录价格的项目,我使用OVER子句并按项目和计量单位进行分区,以获得每个项目/ uom的成员数。然后,我在where子句中使用此计数来过滤掉计数小于1的行。

最后,排序是通过简单的order by子句完成的。完成的tsql脚本如下所示。

    declare @MemberKeys as varchar(max)

    set @MemberKeys = '702,1382,1389,1390,1391,1392,1393,1394,1395,1396,1397,1401,1402,1404,1405,1406,1516,1844';

    create table #mk (memberName varchar(253), memberkey smallint)


    insert into #mk (memberName, memberkey)
    Select Rownbr + '.)  '  +  membername, memberkey from (
    SELECT
        cast(ROW_NUMBER() OVER(ORDER BY [MemberFacilityName] ASC) as varchar (10)) AS RowNbr
        ,k.value as memberkey
        ,m.memberName

    FROM 
        Member m
        INNER JOIN dbo.String_To_SmallInt_Table(@MemberKeys, ',') AS k
        ON m.Memberkey = k.value            
        ) X

    create table #mostrecentpurchase(purchasedate date, itemkey int, uomkey int, memberkey int)

    Insert into #mostrecentpurchase(purchasedate, itemkey, uomkey, memberkey)
    select max(f.PurchaseDate) purchasedate
    , f.itemKey
    , f.uomkey
    , f.memberkey
    from  Fact f
    join #mk m
    on m.memberkey = f.memberkey
    group by f.itemkey
    , f.uomkey
    , f.memberkey


    select x.* FROM (
    select m.memberName
    , i.itemname
    , i.itemkey
    , f.purchasedate
    , sum(f.purchaseamount) as purchaseamount
    , sum(f.quantity) as quantity
    , u.uomname
    , sum(f.purchaseamount)/sum(f.quantity) as price 
    , count(m.memberName) OVER(PARTITION BY i.vendorItem_PK,u.UnitOfmeasure) AS mbrCount
    from 
    fact f
    join #mk m
    on m.memberkey = f.memberkey
    join #mostrecentpurchase mrp
    on mrp.purchasedate = f.PurchaseDate
    and mrp.memberkey = f.memberkey
    and mrp.uomkey = f.uomkey
    and mrp.vendoritemkey = f.itemkey
    join item i
    on i.itemkey = f.itemkey
    join uom u
    on u.uomkey = f.uomkey
    group by m.membername,i.itemname,i.itemkey,f.purchasedate,u.uomname
    ) X
    where mbrCount >= @MemberCompCount
    order by X.itemname, X.memberName


    drop table #mk;
    drop table #mostrecentpurchase;