2013-10-03 24 views
0

У меня есть две таблицы; категорий и продуктов. Для каждой категории я хотел бы подсчитать, сколько продуктов есть во всех своих подкатегориях. Я уже подсчитал, сколько в каждой категории. Пример таблицы:MySQL Количество продуктов из всех подкатегорий

Категории:

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 

Это просто должно быть как выбрать запрос, нет необходимости обновлять базу данных.

Любые идеи?

EDIT: SQL скрипка: http://sqlfiddle.com/#!2/1941a/4/0

+0

вы можете создать SQL скрипку с данными и структурой для этих таблиц http://sqlfiddle.com/? – Maximus2012

+1

Adjacency List Model - это анти-шаблон SQL, читаемый о таблицах Closere и реализующий это, также проанализируйте это http://www.slideshare.net/billkarwin/models-for-hierarchical-data –

+0

Я не вижу ни одной колонки, которая определит подкатегорию , Или я ничего не вижу? –

ответ

1

Если бы это было мне, я бы создать хранимую процедуру. Другим вариантом является цикл с PHP через первый запрос, тогда для каждого идентификатора запускается другой запрос - но такая логика может резко замедлить вашу страницу.

Вот хороший учебник по хранимым процедурам: http://net.tutsplus.com/tutorials/an-introduction-to-stored-procedures/

В основном вы запускаете те же петли я уже упоминал выше, вы бы с PHP (но он работает гораздо быстрее). Процедура хранится в базе данных и может быть вызвана как функция. Результат такой же, как и запрос.

В соответствии с запросом, здесь пример процедуры (или, вернее, она использует два) в моем экземпляре, «ags_orgs» действует аналогично вашим категориям, где есть parentOrgID. «getChildOrgs» также действует как избыточная функция, так как я понятия не имел, сколько уровней я должен был пройти (это было написано для MSSQL - возможно, существуют различия с mySQL). К сожалению, это не означает строки, а скорее данные , Я настоятельно рекомендую следующий учебник или два, чтобы получить лучшее сцепление, как это работает:

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 
+0

Да, любой из них может быть вариантом, ответ будет включен в скрипт экспорта PHP в любом случае, но что вы бы рекомендовали в качестве операторов выбора? – user2231688

+0

В shortcode: 'SELECT * FROM categories' - затем проведите эти результаты с помощью SELECT * FROM категорий WHERE parentID = $ id' и снова пропустите продукты таким же образом. На самом деле нет простого способа сделать это, что я нашел. У меня была очень похожая ситуация с бесконечными уровнями подкатегорий. Единственный способ - создать хранимую процедуру. Я был бы рад дать вам код для этого, дайте мне знать, хотите ли вы пойти по этому маршруту. – Joao

+0

Как уже говорили вам парни. Чтобы получить этот список, вам нужен цикл или хранимая процедура. По одному запросу вы можете получить только один подсчет одной подкатегории –

0

Вы можете это сделать в одном операторе, если у вас есть ограничение на глубину иерархии. Вы сказали, что у вас всего 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; 

Это будет работать для этого запроса, если вы сохраните иерархию в том, как вы делаете, который называется смежности Список. В основном, ParentID - это способ, которым каждый узел записывает свое положение в иерархии.

Существует несколько других способов хранения иерархий, которые позволяют упростить запрос целых деревьев или поддеревьев. Лучшая организация данных зависит от того, какие запросы вы хотите запустить.

Вот еще некоторые ресурсы:

+0

Привет, Билл, спасибо за это, похоже, что-то мне нужно, однако, я не уверен как реализовать это в моей инструкции select. Не могли бы вы посмотреть на мой sqlfiddle и предложить, где я должен это поставить и называть. http://sqlfiddle.com/#!2/1941a/4/0 – user2231688

Смежные вопросы