資料庫原理第二次實驗報告

Rainycolor發表於2024-05-23

目錄
  • 寫在前面
  • 實驗報告要求
  • 任務一(資料庫CAP)
    • 初始化 CAP
    • 1
    • 2
  • 任務二:檢視(資料庫GlobalToyz)
    • 1
    • 2
    • 3
  • 任務三:觸發器(資料庫GlobalToyz)
    • 1
    • 2
    • 測試
  • 任務四:儲存過程與事務(資料庫GlobalToyz)
    • 1
    • 測試
  • 任務五:遊標與SQL(資料庫GlobalToyz)
    • 1
    • 2
  • 參考

寫在前面

因為任務四說的實在是太說得道理了如果沒有歐內的手很難做這個尊尼獲加的哈利路大旋風,於是就去找了老師:

另外本次實驗報告的生成用了 Keldos-Li_typora-latex-theme_ 將Typora偽裝成LaTeX的中文樣式主題,本科生輕量級課程論文撰寫的好幫手。This is a theme disguising Typora into Chinese LaTeX style,超級好用,強推!

實驗報告要求

  1. 列出所有的SQL語句和原始碼;
  2. PL/SQL程式可以有適當的註釋。
  3. 實驗報告中需給出程式碼、結果截圖和對分析結果的文字描述。

任務一(資料庫CAP)

初始化 CAP

按照課件所示進行表的建立:

Use CAP;

CREATE TABLE MONTH
(
    Rank int PRIMARY KEY NOT NULL,
    Month char(8)
);

CREATE TABLE CUSTOMERS
(
	Cid char(8)  PRIMARY KEY NOT NULL,
	Cname varchar(8) NOT NULL,
	City varchar(8),
	Discnt numeric(10,2)
);
CREATE TABLE AGENTS
(
	Aid char(8)  PRIMARY KEY NOT NULL,
	Aname varchar(8) NOT NULL,
	City varchar(8),
	AgentsPercent int
);
CREATE TABLE PRODUCTS
(
	Pid char(8) PRIMARY KEY NOT NULL,
	Pname varchar(8) NOT NULL,
	City varchar(8), 
	Quantity int,
	Price numeric(10,2)
);
CREATE TABLE ORDERS
(
	Ordno char(8)  PRIMARY KEY NOT NULL,
	OrdersMonth varchar(8),
	cid varchar(8) NOT NULL,
	aid varchar(8) NOT NULL,
	pid varchar(8) NOT NULL,
	Qty int,
	Dollars numeric(10, 2)
);

插入一些資料,並對 MONTH 進行初始化:

Use CAP;

INSERT INTO CUSTOMERS VALUES('C001',' TipTip','Duluth', 10.00);
INSERT INTO AGENTS VALUES('A01',' smith','New York', 6);
INSERT INTO PRODUCTS VALUES('P01',' comb','Dallas', 111400, 0.50);

INSERT INTO MONTH VALUES(1, 'Jan.');
INSERT INTO MONTH VALUES(2, 'Feb.');
INSERT INTO MONTH VALUES(3, 'Mar.');
INSERT INTO MONTH VALUES(4, 'Apr.');
INSERT INTO MONTH VALUES(5, 'May.');
INSERT INTO MONTH VALUES(6, 'Jun.');
INSERT INTO MONTH VALUES(7, 'Jul.');
INSERT INTO MONTH VALUES(8, 'Aug.');
INSERT INTO MONTH VALUES(9, 'Sept.');
INSERT INTO MONTH VALUES(10, 'Oct.');
INSERT INTO MONTH VALUES(11, 'Nov.');
INSERT INTO MONTH VALUES(12, 'Dec.');

1

寫一段程式,向表Orders中增加50000條記錄,要求訂單儘可能均勻地分佈在12個月中。

需要保證資料的合法性,考慮首先從 CUSTOMERSAGENTSPRODUCTSMONTH 中各選出一行資料作為插入訂單的引數,實現方法為將上述各表隨機排序後取第一行。

然後按照數字遞增地構造 50000 條資料的編號 00001 ~ 50000,再隨機地構造其他引數後插入。

declare @i int
set @i = 0
while @i < 50000
begin
    declare @cid varchar(8)
    select top 1 @cid = Cid
    from CUSTOMERS
    order by newid()

    declare @aid varchar(8)
    select top 1 @aid = Aid
    from AGENTS
    order by newid()

    declare @pid varchar(8)
    select top 1 @pid = Pid
    from PRODUCTS
    order by newid()

    declare @mon varchar(8)
    select top 1 @mon = Month
    from MONTH
    order by newid()

    declare @oid varchar(8)
    set @oid = @i
    while len(@oid) < 5
        begin
            set @oid = '0' + @oid
        end

    insert into ORDERS values(@oid, @mon, @cid, @aid, @pid, rand() * 10, rand() * 10);
    set @i = @i + 1
end

執行結果:

2

假設在表Orders上經常要執行的一個查詢是“根據給定的月份,查詢該月訂單的總金額”。寫出該查詢的SQL語句,嘗試透過建立索引提高查詢的速度,並對比建立索引前後執行查詢所消耗的時間。

查詢語句:

select sum(Dollars) sum
from ORDERS
where OrdersMonth = 'Jan.'

建立索引語句:

create index OrdersIndexOnMonth
on ORDERS(OrdersMonth)

在(1)建立的表上的執行結果前後時間差異:

[2024-05-22 10:48:22] 在 71 ms (execution: 37 ms, fetching: 34 ms) 內檢索到從 1 開始的 1 行 \(\rightarrow\) [2024-05-22 10:47:58] 在 60 ms (execution: 11 ms, fetching: 49 ms) 內檢索到從 1 開始的 1 行

任務二:檢視(資料庫GlobalToyz)

1

假設GlobalToyz資料庫的使用者經常需要查詢某個購物者(shopper)的所有已收貨訂單的編號和待收貨訂單的編號。請透過定義檢視解決這個問題。

檢視中需要包含 ShopperIdOrderNocDeliveryStatus

create view ViewShopper(cShopperId, cDeliveryStatus, cOrderNo)
as select Shopper.cShopperId, cDeliveryStatus, Orders.cOrderNo
    from Shopper
    left join Orders
    on Shopper.cShopperId = Orders.cShopperId
    left join Shipment
    on Orders.cOrderNo = Shipment.cOrderNo

測試語句:

select cDeliveryStatus, cOrderNo
from ViewShopper
where cShopperId = '000002'

執行結果:

2

基於(1)中定義的檢視,根據給定的購物者Id查詢該購物者所有待收貨玩具的Id,名稱和描述。

假設給定購物者 cShopperId = '000008

select VS.cOrderNo, T.vToyName, T.vToyDescription
from ViewShopper VS
left join Orders O
on VS.cOrderNo = O.cOrderNo
left join ShoppingCart SC
on O.cCartId = SC.cCartId
left join Toys T
on SC.cToyId = T.cToyId
where VS.cShopperId = '000002' and VS.cDeliveryStatus = 's'

執行結果:

3

假設當系統中新增一個購物者(Shopper)的時候,需要為該購物者建立一個賬號,並透過授權機制限制該購物者不能訪問其他購物者的私有資訊,例如其他購物者的訂單、購物者的姓名、地址、郵件等個人資訊。請給出解決的方案。

考慮在系統新增購物者的同時,為每個購物者單獨建立查詢檢視,其中僅包含該購物者的資訊。每次購物者訪問資料庫時,僅允許在該檢視中進行查詢,若嘗試訪問其他購物者的資訊直接丟擲錯誤。

任務三:觸發器(資料庫GlobalToyz)

1

PickofMonth這張表是一張統計表,按年月統計某個玩具的銷售總量。當使用者下訂單的時候,需要自動維護PickofMonth這張表。請利用觸發器實現這個功能。

使用遊標列舉 inserted 表中對應訂單的購物車中的所有物品的 cToyIdsiQty,並根據 dOrderDate 修改 PickofMonth 中的資料,若對應的年份月份不存在則新建一行。

create trigger updatePickOfMonth on Orders
after insert
as
    select year(inserted.dOrderDate) dOrderYear, month(inserted.dOrderDate) dOrderMonth,
           ShoppingCart.cToyId, ShoppingCart.siQty into T
    from inserted
    left join ShoppingCart
    on inserted.cCartId = ShoppingCart.cCartId

--     select *
--     from T

    declare cursor_toy cursor for
    select dOrderYear, dOrderMonth, cToyId, siQty from T
    open cursor_toy;

    declare @year int
    declare @month int
    declare @toy char(6)
    declare @qty smallint
    fetch next from cursor_toy into @year, @month, @toy, @qty;
    WHILE @@FETCH_STATUS = 0
        BEGIN
--             PRINT 'toyid:' + @toy + ',qty:' + CAST(@qty AS varchar(10));
            if exists(select * from PickOfMonth
                               where @year = PickOfMonth.iYear and
                                     @month = PickOfMonth.siMonth and
                                     @toy = PickOfMonth.cToyId)
                begin
                    update PickOfMonth
                    set iTotalSold = iTotalSold + @qty
                    where cToyId = @toy and
                          iYear = @year and
                          siMonth = @month
                end
            else
                begin
                    insert into PickOfMonth values(@toy, @month, @year, @qty)
                end

            FETCH NEXT FROM cursor_toy INTO @year, @month, @toy, @qty;
        END;
    close cursor_toy;
    deallocate cursor_toy;

    drop table T
    go

2

Orders表是GlobalToyz資料庫裡的一張核心的表,對這張表上做的任何更新動作(增、刪、改)都需要記錄下來,這是資料庫審計(Audit)的基本思想。要求設計一張表儲存對Orders表的更新操作,包括操作者、操作時間、操作型別、更新前的資料、更新後的資料。請透過設計觸發器實現對Orders表的審計。

為了記錄更新操作與歷史物件,首先建立如下兩張表:

create table HistoryOrders
(
    historyOrderNo   bigint  not null primary key identity(1, 1),
    cOrderNo         char(6)  not null,
    dOrderDate       datetime not null,
    cCartId          char(6)  not null,
    cShopperId       char(6)  not null,
    cShippingModeId  char(2),
    mShippingCharges money,
    mGiftWrapCharges money,
    cOrderProcessed  char,
    mTotalCost       money,
    dExpDelDate      datetime
)

-- 操作者、操作時間、操作型別、更新前的資料、更新後的資料
create table AuditOrders
(
    Aid bigint PRIMARY KEY NOT NULL identity(1, 1),
    Operator varchar(16) NOT NULL,
    Datetime datetime,
    Type varchar(16),
    BeforeOrderNo bigint,
    AfterOrderNo bigint
)

然後建立如下三個觸發器,分別用於處理增刪改:

  • InsertOrders:將新增資料插入 HistoryOrders,然後將其在 HistoryOrders 中的編號作為引數,將 insert 操作插入 AuditOrders
  • DeleteOrders:將被刪除資料插入 HistoryOrders,然後將其在 HistoryOrders 中的編號作為引數,將 delete 操作插入 AuditOrders
  • UpdateOrders:將被刪除數均插入 HistoryOrders,然後將它們在 HistoryOrders 中的編號作為引數,將 update 操作插入 AuditOrders

特別地,若操作非法,沒有對資料庫造成影響,仍會記錄一次空操作。

-- 增、刪、改
create trigger InsertOrders on Orders
    after insert
    as
    declare @after bigint
    if (select count(*) from inserted) > 0
        begin
            insert into HistoryOrders select * from inserted
            select @after = max(historyOrderNo) from HistoryOrders
        end

    insert into AuditOrders(Operator, Datetime, Type, BeforeOrderNo, AfterOrderNo)
    values (user, getdate(), 'insert', null, @after)
    go


create trigger DeleteOrders on Orders
    after delete
    as
    declare @before bigint
    if (select count(*) from deleted) > 0
        begin
            insert into HistoryOrders select * from deleted
            select @before = max(historyOrderNo)from HistoryOrders
        end

    insert into AuditOrders(Operator, Datetime, Type, BeforeOrderNo, AfterOrderNo)
    values (user, getdate(), 'delete', @before, null)
    go

create trigger UpdateOrders on Orders
    after update
    as
    declare @before bigint
    declare @after bigint
    if (select count(*) from deleted) > 0
        begin
            insert into HistoryOrders select * from deleted
            select @before = max(historyOrderNo) from HistoryOrders

            insert into HistoryOrders select * from inserted
            select @after = max(historyOrderNo) from HistoryOrders
        end

    insert into AuditOrders(Operator, Datetime, Type, BeforeOrderNo, AfterOrderNo)
    values (user, getdate(), 'update', @before, @after)
    go

測試

INSERT INTO GlobalToyz.dbo.Orders (cOrderNo, dOrderDate, cCartId, cShopperId,
                                   cShippingModeId, mShippingCharges, mGiftWrapCharges,
                                   cOrderProcessed, mTotalCost, dExpDelDate)
        VALUES (N'111111', N'2024-05-22 13:38:02.000', N'000002',
                N'000002', N'01', 6.0000, 1.0000, N'Y', 2.0000, N'2024-05-22 13:38:28.000')

update Orders
set mTotalCost = mTotalCost + 1
where Orders.cOrderNo = '95'

delete from Orders
where cOrderNo = '111111'

update Orders
set mTotalCost = mTotalCost + 1
where Orders.cOrderNo = '95'

執行結果:

任務四:儲存過程與事務(資料庫GlobalToyz)

1

當使用者確認了一筆訂單的時候,需要對資料庫進行一系列的操作,例如向表Orders、表OrderDetail中新增記錄、對錶Toys中玩具的庫存數量的修改等,請首先畫出相應的處理流程,然後將處理流程定義為一個事務,透過一個儲存過程來實現,儲存過程以購物車ID(cCartId)和購物者ID(cShopperId)為引數。(這道題請充分考慮確認訂單的各個環節)

最折磨的一集。

只使用購物車 ID 和購物者 ID 為引數顯然不太充分,所以額外地隨機生成了如下引數:

  • 運輸種類
  • 對於每個物品:
    • 是否進行禮物包裝
    • 禮物包裝種類
    • 禮物訊息

以下是一些用於生成隨機資料的函式:

create view v_rand
as
select rand() as val;
go

create or alter function getRandNum(@n int)
    returns int
as begin
    select @n = @n * val from v_rand
    return floor(@n)
end;
go

create or alter function getRandomString(
    @num int,
    @chars varchar(1024) = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
) returns varchar(1024)
as begin
    declare @res_str VARCHAR(1024) = ''
    declare @i int=0
    while (@i < @num) begin
        set @res_str = @res_str + substring(@chars, dbo.getRandNum(len(@chars))+ 1, 1)
        set @i = @i + 1
    end
    return @res_str
end;
go

然後考慮新增一筆訂單後的過程:

  1. 列舉每個物品,在 OrderDetail 插入資料:
    • 隨機引數(是否包裝,包裝種類,禮物訊息)。
    • 計算禮物包裝費用、根據重量計算運輸費用、計算總花費。
    • 將所有花費累計。
  2. Orders 中插入資料:
    • PickOfMonth 更新銷量(續用任務三的觸發器)。
    • Toys 更新現有量 Qoh(quantity on hand)(觸發器實現)
  3. Recipient 插入資料(觸發器實現)
  4. Shipment 插入資料(觸發器實現)
    • 僅插入包含 OrderNo 的空行。
create or alter function getShippingCost(
    @shopperId char(6),
    @modeId char(2),
    @pound smallint
) returns money
as begin
    declare @countryId char(3)
    declare @ratePerPound money
    select @countryId = cCountryID
    from Shopper
    where cShopperId = @shopperId

    select @ratePerPound = mRatePerPound
    from ShippingRate
    where cCountryID = @countryId and cModeId = @modeId

    return convert(money, @ratePerPound * @pound)
end
go

create procedure AddOrder
(
    @shopperId char(6),
    @cartId char(6)
)
as begin
    declare @maxNo int
    select @maxNo = max(cOrderNo) + 1 from Orders

    declare @orderNo char(6)
    declare @shippingModeId char(2)
    declare @shippingCharges money = 0
    declare @giftWrapCharges money = 0
    declare @totalToyCost money = 0
    declare @OrderDate datetime = getdate()
    declare @expDelDate datetime

    set @orderNo = RIGHT('000000' + CAST(@maxNo AS VARCHAR), 6);
    select top 1 @shippingModeId = cModeId,
                 @expDelDate = dateadd(day, iMaxDelDays, @OrderDate)
    from ShippingMode
    order by newid()

    alter table OrderDetail
    nocheck constraint FK__OrderDeta__cOrde__534D60F1

    declare toy_cursor cursor for
    select ShoppingCart.cToyId as cToyId,
           ShoppingCart.siQty as siQty,
           Toys.mToyRate as mToyRate,
           Toys.siToyWeight as siToyWeight
    from ShoppingCart
    left join Toys
    on ShoppingCart.cToyId = Toys.cToyId
    where cCartId = @cartId
    open toy_cursor

    declare @toy char(6)
    declare @qty smallint
    declare @rate money
    declare @weight smallint
    fetch next from toy_cursor into @toy, @qty, @rate, @weight
    while @@fetch_status = 0 begin
        declare @giftWrap char(1) = 'N'
        declare @wrapId char(3)
        declare @message char(256)
        declare @toyCost money = @qty * @rate
        declare @toyWrapCost money = 0
        declare @toyShippingCost money = 0

        if (rand() < 0.5) begin
            select top 1 @wrapId = cWrapperId, @toyWrapCost = mWrapperRate
            from Wrapper
            order by newid()

            set @giftWrap = 'Y'
            set @toyWrapCost = @toyWrapCost * @qty
            set @message = dbo.getRandomString(10,DEFAULT)
            set @toyShippingCost = dbo.getShippingCost(@shopperId,
                                                      @shippingModeId, @qty * @weight)
        end

        print convert(char(6), @orderNo) + ' ' + @toy + ' ' + convert(char(6), @qty) + ' ' +
              @giftWrap + ' ' + @wrapId + ' ' + @message + ' ' +
              convert(char, @toyShippingCost)

        set @shippingCharges = @shippingCharges + @toyShippingCost
        set @giftWrapCharges = @giftWrapCharges + @toyWrapCost
        set @totalToyCost = @totalToyCost + @toyCost

        insert into OrderDetail(cOrderNo, cToyId, siQty, cGiftWrap, cWrapperId,
                                vMessage, mToyCost)
            values (@orderNo, @toy, @qty, @giftWrap, @wrapId,
                    @message, @toyCost)

        fetch next from toy_cursor into @toy, @qty, @rate, @weight
    end
    close toy_cursor
    deallocate toy_cursor

    alter table OrderDetail
    check constraint FK__OrderDeta__cOrde__534D60F1




    insert into Orders(cOrderNo, dOrderDate, cCartId, cShopperId, cShippingModeId,
                       mShippingCharges, mGiftWrapCharges, cOrderProcessed,
                       mTotalCost, dExpDelDate)
    values (@orderNo, @OrderDate, @cartId, @shopperId, @shippingModeId,
            @shippingCharges, @giftWrapCharges, 'Y',
            @totalToyCost + @shippingCharges + @giftWrapCharges, @expDelDate)
end;
go

create trigger updateToysQoh on OrderDetail
after insert as
    declare @toyId char(6)
    declare @toyQty smallint
    select @toyId = cToyId, @toyQty = siQty
    from inserted

    if exists(select * from Toys where Toys.cToyId = @toyId and
                                       Toys.siToyQoh >= @toyQty) begin
        update Toys
        set siToyQoh = siToyQoh - @toyQty
        where cToyId = @toyId
    end
go

create trigger insertRecipient on Orders after insert as
    insert into Recipient
    select cOrderNo, vFirstName, vLastName, vAddress, cCity, cState, cCountryId, cZipCode, cPhone
    from inserted
    left join Shopper
    on inserted.cShopperId = Shopper.cShopperId
go

create trigger insertShipment on Orders after insert as
    insert into Shipment
    select cOrderNo, null, null, null
    from inserted
go

測試

exec AddOrder @shopperId = '000002', @cartId = '000001'

執行結果:

Orders 中的變化:

OrderDetail 中的變化:

Recipient 中的變化:

Shippment 中的變化:

PickofMonth 中的變化:

任務五:遊標與SQL(資料庫GlobalToyz)

1

基於表Orders和Shopper,以下列格式生成報表:(要求用遊標實現)

     購貨人ID   XXX    購貨人姓名   XXX    
     購貨人地址  XXXXXX 
     定單號XXX  定單時間XXX  定單金額XXX
     定單號XXX  定單時間XXX  定單金額XXX

使用兩層迴圈,列舉所有購物者,再列舉 Orders 中該購物者的所有訂單,輸出要求的資訊即可。

注意若某購物者沒有下過訂單,則不輸出。

declare shopper_cursor cursor for
select cShopperId, vFirstName, vLastName, vAddress from Shopper
open shopper_cursor

declare @shopper char(6)
declare @firstname varchar(20)
declare @lastname varchar(20)
declare @address varchar(40)
fetch next from shopper_cursor into @shopper, @firstname, @lastname, @address

while @@fetch_status = 0
    begin
        select cOrderNo, dOrderDate, mTotalCost into TempOrders
        from Orders
        where @shopper = Orders.cShopperId

        declare order_cursor cursor for
        select cOrderNo, dOrderDate, mTotalCost from TempOrders
        open order_cursor

        declare @no char(6)
        declare @date datetime
        declare @cost money
        fetch next from order_cursor into @no, @date, @cost

        if @@fetch_status = 0
            begin
                print 'Shopper Id: ' + @shopper + ' Shopper Name: ' + @firstname + ' ' + @lastname
                print 'Shopper Address: ' + @address
                while @@fetch_status = 0
                    begin
                        print 'Order Id: ' + @no + ' Order Datetime: ' + convert(varchar, @date) + ' Order Cost: ' + convert(varchar, @cost)
                        fetch next from order_cursor into @no, @date, @cost
                    end
                print ''
                print ''
            end
        close order_cursor
        deallocate order_cursor
        drop table TempOrders
        fetch next from shopper_cursor INTO @shopper, @firstname, @lastname, @address
    end

close shopper_cursor
deallocate shopper_cursor

執行結果:

Shopper Id: 000002 Shopper Name: Barbara Johnson
Shopper Address: 227 Beach Ave.
Order Id: 000001 Order Datetime: 05 20 2021 12:00AM Order Cost: 62.22
Order Id: 000005 Order Datetime: 05 21 2021 12:00AM Order Cost: 231.68
Order Id: 000011 Order Datetime: 05 23 2024  8:27PM Order Cost: 53.97


Shopper Id: 000003 Shopper Name: Betty Williams
Shopper Address: 1 Tread Road
Order Id: 000010 Order Datetime: 05 22 2021 12:00AM Order Cost: 67.97


Shopper Id: 000005 Shopper Name: Catherine Roberts
Shopper Address: 5508 Aquiline Court
Order Id: 000002 Order Datetime: 05 20 2021 12:00AM Order Cost: 96.50


Shopper Id: 000006 Shopper Name: Charles Brown
Shopper Address: 7822 S. Glitzy Avenue
Order Id: 000004 Order Datetime: 05 20 2021 12:00AM Order Cost: 40.99


Shopper Id: 000007 Shopper Name: Christopher Davis
Shopper Address: 4896 11th ST
Order Id: 000003 Order Datetime: 05 20 2021 12:00AM Order Cost: 83.97


Shopper Id: 000008 Shopper Name: Cynthia Miller
Shopper Address: 98066 Weary Storm Street
Order Id: 000007 Order Datetime: 05 22 2021 12:00AM Order Cost: 16.99


Shopper Id: 000009 Shopper Name: Daniel Wilson
Shopper Address: 4642 Peripheral Drive
Order Id: 000008 Order Datetime: 05 22 2021 12:00AM Order Cost: 53.98


Shopper Id: 000010 Shopper Name: David Moore
Shopper Address: 8808 Joviality Drive
Order Id: 000009 Order Datetime: 05 22 2021 12:00AM Order Cost: 26.99


Shopper Id: 000012 Shopper Name: Donna Anderson
Shopper Address: 7930 Orange St.
Order Id: 000006 Order Datetime: 05 21 2021 12:00AM Order Cost: 97.97

2

編寫程式碼,分析購物者、玩具和地域的關係,例如哪個城市的購買者對哪一種、哪一類或哪一個品牌的玩具更有興趣。這道題是個開放的題目,同學們可以按照自己的理解從不同的角度進行分析。

探究玩具品牌與購買者所在州的關係。

考慮分析每種品牌在各個州的銷售額在總銷售額的佔比,並按照降序排序:

-- 計算每種品牌玩具銷售量總和
select Toys.cBrandId, convert(money, sum(siQty)) sum into T
from Toys
left join OrderDetail OD on Toys.cToyId = OD.cToyId
group by Toys.cBrandId

-- 求銷售額在各州佔比
select Toys.cBrandId, Shopper.cState,
       convert(money, sum(siQty)) / (select sum from T where Toys.cBrandId = T.cBrandId) sum
from OrderDetail OD
left join Orders O on OD.cOrderNo = O.cOrderNo
left join Toys on Toys.cToyId = OD.cToyId
left join Shopper on O.cShopperId = Shopper.cShopperId
group by Shopper.cState, Toys.cBrandId
order by Toys.cBrandId, sum desc

drop table T

執行結果:

發現每種玩具均在加州的銷售額的佔比最高。你們加州可真是人才輩出啊(讚美之心

不行了提到加州就想到睦月跳那個鑄幣 California Girls 我草

參考

主要參考:資料庫原理及應用教程 第4版︱微課版 (陳志泊 許福 韓慧 崔曉暉 路賀俊 阮豫紅編著)

語句參考:

  • SQL server 自定義函式FUNCTION的使用_sqlserver function-CSDN部落格
  • SQL 如何建立索引來加快資料庫的查詢_sql建立索引加速查詢-CSDN部落格
  • SQL SERVER中使用print如何一起輸出數值和字串_sql server print-CSDN部落格
  • 變數 (Transact-SQL) - SQL Server _ Microsoft Learn
  • SQL INSERT INTO 語句 _ 菜鳥教程
  • SQL UPDATE 語句 _ 菜鳥教程
  • SQL Server 臨時禁用和啟用所有外來鍵約束_sqlserver 臨時禁用表訂閱-CSDN部落格
  • SQLServer禁用、啟用外來鍵約束 - 振乾 - 部落格園
  • 在 INSERT 和 UPDATE 語句中禁用外來鍵約束 - SQL Server _ Microsoft Learn
  • 玩轉SQL語句之group by 多欄位分組查詢與having子句,一篇解決你的疑惑!_sql group by-CSDN部落格
  • SQL ORDER BY 子句【排序】升降序_sql排序語句order by升序-CSDN部落格
  • sql server生成自動加1序號_mob649e8166179a的技術部落格_51CTO部落格
  • SQL Server Year()函式 - SQL Server教程
  • SQL Server YEAR() 函式使用指南

寫法參考:

  • SQL 在SQL Server表中如何獲取第n行_極客教程

  • Sql Server 對資料表迴圈插入多條資料(使用迴圈方法給資料表插入資料)_給sql server資料庫持續寫入資料的方法-CSDN部落格

  • SQL 查詢從表中提取隨機行_極客教程

  • Microsoft SQL Server 生成隨機數字、字串、日期、驗證碼以及 UUID_sql server 驗證碼-CSDN部落格

  • MySQL 使用觸發器記錄使用者的操作日誌_在emp表中的資料被刪除時,就會把執行這個動作的使用者和時間,以及被刪除的人名記錄-CSDN部落格

  • MySQL常用查詢(查行數、列數、表數、欄位數)和常用函式-CSDN部落格

  • SQL – 遍歷表格記錄_極客教程

  • SQL 在SQL Server中使用前導零來格式化數字_極客教程

捉蟲參考:

  • SQL Server錯誤443:在函式內對帶副作用的運算子 'rand' 的使用無效 - HandsomeFa - 部落格園
  • 解決為'_________' 的遊標已存在問題_名為 的遊標已存在-CSDN部落格
  • sql語句報錯:“不是可以識別的內建函式名稱”_sql不是可以識別的內建函式名稱-CSDN部落格

實驗報告格式:

  • Keldos-Li_typora-latex-theme_ 將Typora偽裝成LaTeX的中文樣式主題,本科生輕量級課程論文撰寫的好幫手。This is a theme disguising Typora into Chinese LaTeX style

相關文章