0

2 つのテーブルがあります。カテゴリと製品。カテゴリごとに、そのすべてのサブカテゴリに含まれる製品の数を数えたいと思います。各カテゴリに何人いるかはすでに数えています。テーブルの例は次のとおりです。

カテゴリー:

ID  ParentID  ProductCount  SubCategoryProducts
1   NULL      0
2   1         2
3   2         1

製品:

ProductID  CategoryID
123        2
124        2
125        3

だから私は自分の関数を作りたい:

ID  ParentID  ProductCount  SubCategoryProducts
1   NULL      0             3
2   1         2             1
3   2         1             0

データベースを更新する必要はありません。

何か案は?

編集: SQL Fiddle: http://sqlfiddle.com/#!2/1941a/4/0

4

4 に答える 4

1

私だったら、ストアド プロシージャを作成します。もう 1 つのオプションは、PHP で最初のクエリをループしてから、ID ごとに別のクエリを実行することですが、この種のロジックではページが大幅に遅くなる可能性があります。

ストアド プロシージャに関するすばらしいチュートリアルがあります: http://net.tutsplus.com/tutorials/an-introduction-to-stored-procedures/

基本的には、上記で述べたのと同じループを実行します (ただし、はるかに高速に実行されます)。プロシージャはデータベースに格納され、関数のように呼び出すことができます。結果はクエリと同じです。

リクエストに応じて、ここに私の例でのサンプル プロシージャ (または 2 つを使用) を示します。「ags_orgs」は、parentOrgID があるカテゴリと同様に機能します。「getChildOrgs」も冗長な関数のように機能します。これは、何レベル下に移動する必要があるか分からなかったからです (これは MSSQL 用に作成されたもので、おそらく mySQL との違いがあります)。残念ながら、これは行をカウントせず、むしろデータを取得します。 . それがどのように機能するかをよりよく理解するために、1つか2つのチュートリアルに従うことを強くお勧めします。

USE [dbname]
GO

/****** Object:  StoredProcedure [dbo].[getChildOrgs]    Script Date: 09/26/2012 15:30:06 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[getChildOrgs]

@myParentID int,
@isActive tinyint = NULL

AS
BEGIN

    SET NOCOUNT ON
    DECLARE @orgID int, @orgName varchar(255), @level int

        DECLARE cur CURSOR LOCAL FOR SELECT orgID FROM dbo.ags_orgs WHERE parentOrgID = @myParentID AND isActive = ISNULL(@isActive, isActive) ORDER BY orderNum, orgName


    OPEN cur
        fetch next from cur into @orgID
    WHILE @@fetch_status = 0
    BEGIN
        INSERT INTO #temp_childOrgs SELECT orgID,orgName,description,parentOrgID,adminID,isActive,@@NESTLEVEL-1 AS level  FROM dbo.ags_orgs WHERE orgID = @orgID

        EXEC getChildOrgs @orgID, @isActive
        -- get next result
        fetch next from cur into @orgID
    END
    CLOSE cur
    DEALLOCATE cur

END

GO

このプロシージャによって呼び出されるもの:

USE [dbname]
GO

/****** Object:  StoredProcedure [dbo].[execGetChildOrgs]    Script Date: 09/26/2012 15:29:34 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[execGetChildOrgs]

@parentID int,
@isActive tinyint = NULL,
@showParent tinyint = NULL

AS

BEGIN

CREATE TABLE #temp_childOrgs
(
   orgID int,
   orgName varchar(255),
   description text,
   parentOrgID int,
   adminID int,
   isActive tinyint,
   level int
)
-- if this isn't AGS top level (0), make the first record reflect the requested organization
IF @parentID != 0 AND @showParent = 1
BEGIN
    INSERT INTO #temp_childOrgs SELECT orgID,orgName,description,parentOrgID,adminID,isActive,0 AS level  FROM dbo.ags_orgs WHERE orgID = @parentID
END

exec getChildOrgs @parentID, @isActive

SELECT * FROM #temp_childOrgs
DROP TABLE #temp_childOrgs
END

GO
于 2013-10-03T19:10:24.633 に答える
0

階層の深さに制限がある場合は、これを 1 つのステートメントで行うことができます。あなたは合計で 4 つのレベルしかないと言いました。

SELECT SUM(ProductCount)
FROM (
    SELECT c0.ID, c0.ProductCount
    FROM Categories AS c0
    WHERE c0.ID = 1
    UNION ALL
    SELECT c1.ID, c1.ProductCount
    FROM Categories AS c0
    JOIN Categories AS c1 ON c0.ID = c1.ParentID
    WHERE c0.ID = 1
    UNION ALL
    SELECT c2.ID, c2.ProductCount
    FROM Categories AS c0
    JOIN Categories AS c1 ON c0.ID = c1.ParentID
    JOIN Categories AS c2 ON c1.ID = c2.ParentID
    WHERE c0.ID = 1
    UNION ALL
    SELECT c3.ID, c3.ProductCount
    FROM Categories AS c0
    JOIN Categories AS c1 ON c0.ID = c1.ParentID
    JOIN Categories AS c2 ON c1.ID = c2.ParentID
    JOIN Categories AS c3 ON c2.ID = c3.ParentID
    WHERE c0.ID = 1
) AS _hier;

Adjacency Listと呼ばれる方法で階層を保存すると、このクエリで機能します。基本的に、これParentIDは各ノードが階層内での位置を記録する方法です。

ツリー全体またはサブツリーの簡単なクエリを可能にする、階層を格納する方法が他にもいくつかあります。最適なデータ編成は、実行するクエリによって異なります。

その他のリソースを次に示します。

于 2013-10-03T23:43:32.113 に答える