feat(sql): update queries to support individual items and fix schema drop order
This commit is contained in:
@@ -17,10 +17,10 @@ SELECT
|
||||
{% block total_sets %}
|
||||
NULL AS "total_sets" -- dummy for order: total_sets
|
||||
{% endblock %}
|
||||
FROM "bricktracker_minifigures"
|
||||
FROM "rebrickable_minifigures"
|
||||
|
||||
INNER JOIN "rebrickable_minifigures"
|
||||
ON "bricktracker_minifigures"."figure" IS NOT DISTINCT FROM "rebrickable_minifigures"."figure"
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "rebrickable_minifigures"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
|
||||
{% block join %}{% endblock %}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ IFNULL("problem_join"."total_damaged", 0) AS "total_damaged",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
SUM(IFNULL("bricktracker_minifigures"."quantity", 0)) AS "total_quantity",
|
||||
SUM(IFNULL("bricktracker_minifigures"."quantity", 0)) + SUM(IFNULL("individual_minifigures_join"."quantity", 0)) AS "total_quantity",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_sets %}
|
||||
@@ -28,6 +28,17 @@ LEFT JOIN (
|
||||
GROUP BY "bricktracker_parts"."figure"
|
||||
) "problem_join"
|
||||
ON "rebrickable_minifigures"."figure" IS NOT DISTINCT FROM "problem_join"."figure"
|
||||
|
||||
-- LEFT JOIN to include individual minifigure instances (not in sets)
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_individual_minifigures"."figure",
|
||||
SUM("bricktracker_individual_minifigures"."quantity") AS "quantity"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
WHERE "bricktracker_individual_minifigures"."figure" IS NOT DISTINCT FROM :figure
|
||||
GROUP BY "bricktracker_individual_minifigures"."figure"
|
||||
) "individual_minifigures_join"
|
||||
ON "rebrickable_minifigures"."figure" IS NOT DISTINCT FROM "individual_minifigures_join"."figure"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
"bricktracker_parts"."figure",
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare",
|
||||
"bricktracker_parts"."quantity",
|
||||
"bricktracker_parts"."element",
|
||||
--"bricktracker_parts"."rebrickable_inventory",
|
||||
"bricktracker_parts"."missing",
|
||||
"bricktracker_parts"."damaged",
|
||||
"bricktracker_parts"."checked",
|
||||
--"rebrickable_parts"."part",
|
||||
--"rebrickable_parts"."color_id",
|
||||
"combined"."id",
|
||||
"combined"."figure",
|
||||
"combined"."part",
|
||||
"combined"."color",
|
||||
"combined"."spare",
|
||||
"combined"."quantity",
|
||||
"combined"."element",
|
||||
"combined"."missing",
|
||||
"combined"."damaged",
|
||||
"combined"."checked",
|
||||
"rebrickable_parts"."color_name",
|
||||
"rebrickable_parts"."color_rgb",
|
||||
"rebrickable_parts"."color_transparent",
|
||||
@@ -19,7 +16,6 @@ SELECT
|
||||
"rebrickable_parts"."bricklink_color_name",
|
||||
"rebrickable_parts"."bricklink_part_num",
|
||||
"rebrickable_parts"."name",
|
||||
--"rebrickable_parts"."category",
|
||||
"rebrickable_parts"."image",
|
||||
"rebrickable_parts"."image_id",
|
||||
"rebrickable_parts"."url",
|
||||
@@ -42,11 +38,62 @@ SELECT
|
||||
{% block total_minifigures %}
|
||||
NULL AS "total_minifigures" -- dummy for order: total_minifigures
|
||||
{% endblock %}
|
||||
FROM "bricktracker_parts"
|
||||
FROM (
|
||||
-- Parts from set-based minifigures
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
"bricktracker_parts"."figure",
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare",
|
||||
"bricktracker_parts"."quantity",
|
||||
"bricktracker_parts"."element",
|
||||
"bricktracker_parts"."missing",
|
||||
"bricktracker_parts"."damaged",
|
||||
"bricktracker_parts"."checked",
|
||||
'set' AS "source_type"
|
||||
FROM "bricktracker_parts"
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Parts from individual minifigures
|
||||
SELECT
|
||||
"bricktracker_individual_minifigure_parts"."id",
|
||||
"bricktracker_individual_minifigures"."figure",
|
||||
"bricktracker_individual_minifigure_parts"."part",
|
||||
"bricktracker_individual_minifigure_parts"."color",
|
||||
"bricktracker_individual_minifigure_parts"."spare",
|
||||
"bricktracker_individual_minifigure_parts"."quantity",
|
||||
"bricktracker_individual_minifigure_parts"."element",
|
||||
"bricktracker_individual_minifigure_parts"."missing",
|
||||
"bricktracker_individual_minifigure_parts"."damaged",
|
||||
"bricktracker_individual_minifigure_parts"."checked",
|
||||
'individual_minifigure' AS "source_type"
|
||||
FROM "bricktracker_individual_minifigure_parts"
|
||||
INNER JOIN "bricktracker_individual_minifigures"
|
||||
ON "bricktracker_individual_minifigure_parts"."id" = "bricktracker_individual_minifigures"."id"
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Individual/standalone parts (not from any set or minifigure)
|
||||
SELECT
|
||||
"bricktracker_individual_parts"."id",
|
||||
NULL AS "figure",
|
||||
"bricktracker_individual_parts"."part",
|
||||
"bricktracker_individual_parts"."color",
|
||||
0 AS "spare",
|
||||
"bricktracker_individual_parts"."quantity",
|
||||
NULL AS "element",
|
||||
"bricktracker_individual_parts"."missing",
|
||||
"bricktracker_individual_parts"."damaged",
|
||||
"bricktracker_individual_parts"."checked",
|
||||
'individual_part' AS "source_type"
|
||||
FROM "bricktracker_individual_parts"
|
||||
) AS "combined"
|
||||
|
||||
INNER JOIN "rebrickable_parts"
|
||||
ON "bricktracker_parts"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
|
||||
ON "combined"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
|
||||
AND "combined"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
|
||||
|
||||
{% block join %}{% endblock %}
|
||||
|
||||
|
||||
@@ -1,16 +1,40 @@
|
||||
SELECT DISTINCT
|
||||
"rebrickable_parts"."color_id" AS "color_id",
|
||||
"rebrickable_parts"."color_name" AS "color_name",
|
||||
"rebrickable_parts"."color_rgb" AS "color_rgb"
|
||||
FROM "rebrickable_parts"
|
||||
INNER JOIN "bricktracker_parts"
|
||||
ON "bricktracker_parts"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
INNER JOIN "bricktracker_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
INNER JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
WHERE "bricktracker_set_owners"."owner_{{ owner_id }}" = 1
|
||||
{% endif %}
|
||||
ORDER BY "rebrickable_parts"."color_name" ASC
|
||||
"color_id",
|
||||
"color_name",
|
||||
"color_rgb"
|
||||
FROM (
|
||||
-- Colors from set-based parts
|
||||
SELECT DISTINCT
|
||||
"rebrickable_parts"."color_id" AS "color_id",
|
||||
"rebrickable_parts"."color_name" AS "color_name",
|
||||
"rebrickable_parts"."color_rgb" AS "color_rgb"
|
||||
FROM "rebrickable_parts"
|
||||
INNER JOIN "bricktracker_parts"
|
||||
ON "bricktracker_parts"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
INNER JOIN "bricktracker_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
INNER JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
WHERE "bricktracker_set_owners"."owner_{{ owner_id }}" = 1
|
||||
{% endif %}
|
||||
|
||||
UNION
|
||||
|
||||
-- Colors from individual parts
|
||||
SELECT DISTINCT
|
||||
"rebrickable_parts"."color_id" AS "color_id",
|
||||
"rebrickable_parts"."color_name" AS "color_name",
|
||||
"rebrickable_parts"."color_rgb" AS "color_rgb"
|
||||
FROM "rebrickable_parts"
|
||||
INNER JOIN "bricktracker_individual_parts"
|
||||
ON "bricktracker_individual_parts"."part" IS NOT DISTINCT FROM "rebrickable_parts"."part"
|
||||
AND "bricktracker_individual_parts"."color" IS NOT DISTINCT FROM "rebrickable_parts"."color_id"
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
INNER JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_individual_parts"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
WHERE "bricktracker_set_owners"."owner_{{ owner_id }}" = 1
|
||||
{% endif %}
|
||||
)
|
||||
ORDER BY "color_name" ASC
|
||||
@@ -1,55 +1,60 @@
|
||||
{% extends 'part/base/base.sql' %}
|
||||
|
||||
{% block total_missing %}
|
||||
SUM("bricktracker_parts"."missing") AS "total_missing",
|
||||
SUM("combined"."missing") AS "total_missing",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
SUM("bricktracker_parts"."damaged") AS "total_damaged",
|
||||
SUM("combined"."damaged") AS "total_damaged",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
SUM("bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)) AS "total_quantity",
|
||||
SUM("combined"."quantity" * IFNULL("minifigure_quantities"."quantity", 1)) AS "total_quantity",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_sets %}
|
||||
IFNULL(COUNT(DISTINCT "bricktracker_parts"."id"), 0) AS "total_sets",
|
||||
IFNULL(COUNT(DISTINCT CASE WHEN "combined"."source_type" = 'set' THEN "combined"."id" ELSE NULL END), 0) AS "total_sets",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_minifigures %}
|
||||
SUM(IFNULL("bricktracker_minifigures"."quantity", 0)) AS "total_minifigures"
|
||||
SUM(IFNULL("minifigure_quantities"."quantity", 0)) AS "total_minifigures"
|
||||
{% endblock %}
|
||||
|
||||
{% block join %}
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
-- Join to get minifigure quantities from both set-based and individual minifigures
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
"bricktracker_minifigures"."figure",
|
||||
"bricktracker_minifigures"."quantity"
|
||||
FROM "bricktracker_minifigures"
|
||||
|
||||
{% if theme_id or year %}
|
||||
INNER JOIN "bricktracker_sets" AS "filter_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "filter_sets"."id"
|
||||
INNER JOIN "rebrickable_sets" AS "filter_rs"
|
||||
ON "filter_sets"."set" IS NOT DISTINCT FROM "filter_rs"."set"
|
||||
{% endif %}
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
"bricktracker_individual_minifigures"."id",
|
||||
"bricktracker_individual_minifigures"."figure",
|
||||
"bricktracker_individual_minifigures"."quantity"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
) AS "minifigure_quantities"
|
||||
ON "combined"."id" IS NOT DISTINCT FROM "minifigure_quantities"."id"
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM "minifigure_quantities"."figure"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
{% if color_id and color_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."color" = ' ~ color_id) %}
|
||||
{% endif %}
|
||||
{% if theme_id and theme_id != 'all' %}
|
||||
{% set _ = conditions.append('"filter_rs"."theme_id" = ' ~ theme_id) %}
|
||||
{% endif %}
|
||||
{% if year and year != 'all' %}
|
||||
{% set _ = conditions.append('"filter_rs"."year" = ' ~ year) %}
|
||||
{% set _ = conditions.append('"combined"."color" = ' ~ color_id) %}
|
||||
{% endif %}
|
||||
{% if search_query %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("bricktracker_parts"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("combined"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set _ = conditions.append(search_condition) %}
|
||||
{% endif %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% set _ = conditions.append('"combined"."spare" = 0') %}
|
||||
{% endif %}
|
||||
{% if individuals_filter %}
|
||||
{% set _ = conditions.append('"combined"."source_type" = \'individual_part\'') %}
|
||||
{% endif %}
|
||||
{% if conditions %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
@@ -58,7 +63,7 @@ WHERE {{ conditions | join(' AND ') }}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare"
|
||||
"combined"."part",
|
||||
"combined"."color",
|
||||
"combined"."spare"
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,73 +2,136 @@
|
||||
|
||||
{% block total_missing %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."missing" ELSE 0 END) AS "total_missing",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."missing"
|
||||
WHEN "combined"."source_type" = 'individual_minifigure' AND "individual_minifigure_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."missing"
|
||||
WHEN "combined"."source_type" = 'individual_part' AND ("individual_part_owners"."owner_{{ owner_id }}" = 1 OR "individual_part_lot_owners"."owner_{{ owner_id }}" = 1) THEN "combined"."missing"
|
||||
ELSE 0
|
||||
END) AS "total_missing",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."missing") AS "total_missing",
|
||||
SUM("combined"."missing") AS "total_missing",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."damaged" ELSE 0 END) AS "total_damaged",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."damaged"
|
||||
WHEN "combined"."source_type" = 'individual_minifigure' AND "individual_minifigure_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."damaged"
|
||||
WHEN "combined"."source_type" = 'individual_part' AND ("individual_part_owners"."owner_{{ owner_id }}" = 1 OR "individual_part_lot_owners"."owner_{{ owner_id }}" = 1) THEN "combined"."damaged"
|
||||
ELSE 0
|
||||
END) AS "total_damaged",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."damaged") AS "total_damaged",
|
||||
SUM("combined"."damaged") AS "total_damaged",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1) ELSE 0 END) AS "total_quantity",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)
|
||||
WHEN "combined"."source_type" = 'individual_minifigure' AND "individual_minifigure_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."quantity"
|
||||
WHEN "combined"."source_type" = 'individual_part' AND ("individual_part_owners"."owner_{{ owner_id }}" = 1 OR "individual_part_lot_owners"."owner_{{ owner_id }}" = 1) THEN "combined"."quantity"
|
||||
ELSE 0
|
||||
END) AS "total_quantity",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)) AS "total_quantity",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' THEN "combined"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)
|
||||
ELSE "combined"."quantity"
|
||||
END) AS "total_quantity",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_sets %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
COUNT(DISTINCT CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."id" ELSE NULL END) AS "total_sets",
|
||||
COUNT(DISTINCT CASE WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."id" ELSE NULL END) AS "total_sets",
|
||||
{% else %}
|
||||
COUNT(DISTINCT "bricktracker_parts"."id") AS "total_sets",
|
||||
COUNT(DISTINCT CASE WHEN "combined"."source_type" = 'set' THEN "combined"."id" ELSE NULL END) AS "total_sets",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_minifigures %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN IFNULL("bricktracker_minifigures"."quantity", 0) ELSE 0 END) AS "total_minifigures"
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN IFNULL("bricktracker_minifigures"."quantity", 0)
|
||||
WHEN "combined"."source_type" = 'individual_minifigure' AND "individual_minifigure_owners"."owner_{{ owner_id }}" = 1 THEN 1
|
||||
ELSE 0
|
||||
END) AS "total_minifigures"
|
||||
{% else %}
|
||||
SUM(IFNULL("bricktracker_minifigures"."quantity", 0)) AS "total_minifigures"
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' THEN IFNULL("bricktracker_minifigures"."quantity", 0)
|
||||
WHEN "combined"."source_type" = 'individual_minifigure' THEN 1
|
||||
ELSE 0
|
||||
END) AS "total_minifigures"
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block join %}
|
||||
-- Join with sets to get owner information
|
||||
INNER JOIN "bricktracker_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
-- Left join with sets (for set-based parts)
|
||||
LEFT JOIN "bricktracker_sets"
|
||||
ON "combined"."source_type" = 'set'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
|
||||
-- Left join with set owners (using dynamic columns)
|
||||
LEFT JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
ON "combined"."source_type" = 'set'
|
||||
AND "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
|
||||
-- Left join with minifigures
|
||||
-- Left join with set-based minifigures
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
ON "combined"."source_type" = 'set'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
|
||||
-- Left join with individual minifigures (for individual minifigure parts)
|
||||
LEFT JOIN "bricktracker_individual_minifigures"
|
||||
ON "combined"."source_type" = 'individual_minifigure'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_individual_minifigures"."id"
|
||||
|
||||
-- Left join with set owners for individual minifigures (using dynamic columns) - reuse set_owners table
|
||||
LEFT JOIN "bricktracker_set_owners" AS "individual_minifigure_owners"
|
||||
ON "combined"."source_type" = 'individual_minifigure'
|
||||
AND "bricktracker_individual_minifigures"."id" IS NOT DISTINCT FROM "individual_minifigure_owners"."id"
|
||||
|
||||
-- Left join with individual parts (for standalone parts and lot parts)
|
||||
LEFT JOIN "bricktracker_individual_parts"
|
||||
ON "combined"."source_type" = 'individual_part'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_individual_parts"."id"
|
||||
|
||||
-- Left join with set owners for individual parts (using dynamic columns) - for standalone parts
|
||||
LEFT JOIN "bricktracker_set_owners" AS "individual_part_owners"
|
||||
ON "combined"."source_type" = 'individual_part'
|
||||
AND "bricktracker_individual_parts"."id" IS NOT DISTINCT FROM "individual_part_owners"."id"
|
||||
|
||||
-- Left join with individual part lots (for parts belonging to a lot)
|
||||
LEFT JOIN "bricktracker_individual_part_lots"
|
||||
ON "combined"."source_type" = 'individual_part'
|
||||
AND "bricktracker_individual_parts"."lot_id" IS NOT DISTINCT FROM "bricktracker_individual_part_lots"."id"
|
||||
|
||||
-- Left join with set owners for individual part lots (using dynamic columns)
|
||||
LEFT JOIN "bricktracker_set_owners" AS "individual_part_lot_owners"
|
||||
ON "combined"."source_type" = 'individual_part'
|
||||
AND "bricktracker_individual_part_lots"."id" IS NOT DISTINCT FROM "individual_part_lot_owners"."id"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_set_owners"."owner_' ~ owner_id ~ '" = 1') %}
|
||||
{% set owner_condition = '(("combined"."source_type" = \'set\' AND "bricktracker_set_owners"."owner_' ~ owner_id ~ '" = 1) OR ("combined"."source_type" = \'individual_minifigure\' AND "individual_minifigure_owners"."owner_' ~ owner_id ~ '" = 1) OR ("combined"."source_type" = \'individual_part\' AND ("individual_part_owners"."owner_' ~ owner_id ~ '" = 1 OR "individual_part_lot_owners"."owner_' ~ owner_id ~ '" = 1)))' %}
|
||||
{% set _ = conditions.append(owner_condition) %}
|
||||
{% endif %}
|
||||
{% if color_id and color_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."color" = ' ~ color_id) %}
|
||||
{% set _ = conditions.append('"combined"."color" = ' ~ color_id) %}
|
||||
{% endif %}
|
||||
{% if search_query %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("bricktracker_parts"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("combined"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set _ = conditions.append(search_condition) %}
|
||||
{% endif %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% set _ = conditions.append('"combined"."spare" = 0') %}
|
||||
{% endif %}
|
||||
{% if individuals_filter %}
|
||||
{% set _ = conditions.append('"combined"."source_type" = \'individual_part\'') %}
|
||||
{% endif %}
|
||||
{% if conditions %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
@@ -77,7 +140,7 @@ WHERE {{ conditions | join(' AND ') }}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare"
|
||||
"combined"."part",
|
||||
"combined"."color",
|
||||
"combined"."spare"
|
||||
{% endblock %}
|
||||
@@ -1,26 +1,88 @@
|
||||
-- Query parts from both set-based and individual minifigures
|
||||
SELECT
|
||||
"parts_combined"."id",
|
||||
"parts_combined"."figure",
|
||||
"parts_combined"."part",
|
||||
"parts_combined"."color",
|
||||
"parts_combined"."spare",
|
||||
SUM("parts_combined"."quantity") AS "quantity",
|
||||
"parts_combined"."element",
|
||||
SUM("parts_combined"."missing") AS "total_missing",
|
||||
SUM("parts_combined"."damaged") AS "total_damaged",
|
||||
MAX("parts_combined"."checked") AS "checked",
|
||||
"rebrickable_parts"."color_name",
|
||||
"rebrickable_parts"."color_rgb",
|
||||
"rebrickable_parts"."color_transparent",
|
||||
"rebrickable_parts"."bricklink_color_id",
|
||||
"rebrickable_parts"."bricklink_color_name",
|
||||
"rebrickable_parts"."bricklink_part_num",
|
||||
"rebrickable_parts"."name",
|
||||
"rebrickable_parts"."image",
|
||||
"rebrickable_parts"."image_id",
|
||||
"rebrickable_parts"."url",
|
||||
"rebrickable_parts"."print",
|
||||
NULL AS "total_quantity",
|
||||
NULL AS "total_spare",
|
||||
NULL AS "total_sets",
|
||||
NULL AS "total_minifigures"
|
||||
FROM (
|
||||
-- Set-based minifigure parts
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
"bricktracker_parts"."figure",
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare",
|
||||
"bricktracker_parts"."quantity",
|
||||
"bricktracker_parts"."element",
|
||||
"bricktracker_parts"."missing",
|
||||
"bricktracker_parts"."damaged",
|
||||
"bricktracker_parts"."checked"
|
||||
FROM "bricktracker_parts"
|
||||
WHERE "bricktracker_parts"."figure" IS NOT DISTINCT FROM :figure
|
||||
|
||||
{% extends 'part/base/base.sql' %}
|
||||
UNION ALL
|
||||
|
||||
{% block total_missing %}
|
||||
SUM("bricktracker_parts"."missing") AS "total_missing",
|
||||
{% endblock %}
|
||||
-- Individual minifigure parts
|
||||
SELECT
|
||||
"bricktracker_individual_minifigure_parts"."id",
|
||||
"bricktracker_individual_minifigures"."figure",
|
||||
"bricktracker_individual_minifigure_parts"."part",
|
||||
"bricktracker_individual_minifigure_parts"."color",
|
||||
"bricktracker_individual_minifigure_parts"."spare",
|
||||
"bricktracker_individual_minifigure_parts"."quantity",
|
||||
"bricktracker_individual_minifigure_parts"."element",
|
||||
"bricktracker_individual_minifigure_parts"."missing",
|
||||
"bricktracker_individual_minifigure_parts"."damaged",
|
||||
"bricktracker_individual_minifigure_parts"."checked"
|
||||
FROM "bricktracker_individual_minifigure_parts"
|
||||
INNER JOIN "bricktracker_individual_minifigures"
|
||||
ON "bricktracker_individual_minifigure_parts"."id" = "bricktracker_individual_minifigures"."id"
|
||||
WHERE "bricktracker_individual_minifigures"."figure" IS NOT DISTINCT FROM :figure
|
||||
) AS "parts_combined"
|
||||
|
||||
{% block total_damaged %}
|
||||
SUM("bricktracker_parts"."damaged") AS "total_damaged",
|
||||
{% endblock %}
|
||||
INNER JOIN "rebrickable_parts"
|
||||
ON "parts_combined"."part" = "rebrickable_parts"."part"
|
||||
AND "parts_combined"."color" = "rebrickable_parts"."color_id"
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."figure" IS NOT DISTINCT FROM :figure') %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% endif %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare"
|
||||
{% endblock %}
|
||||
"parts_combined"."part",
|
||||
"parts_combined"."color",
|
||||
"parts_combined"."spare",
|
||||
"parts_combined"."element",
|
||||
"rebrickable_parts"."color_name",
|
||||
"rebrickable_parts"."color_rgb",
|
||||
"rebrickable_parts"."color_transparent",
|
||||
"rebrickable_parts"."bricklink_color_id",
|
||||
"rebrickable_parts"."bricklink_color_name",
|
||||
"rebrickable_parts"."bricklink_part_num",
|
||||
"rebrickable_parts"."name",
|
||||
"rebrickable_parts"."image",
|
||||
"rebrickable_parts"."image_id",
|
||||
"rebrickable_parts"."url",
|
||||
"rebrickable_parts"."print"
|
||||
|
||||
{% if order %}
|
||||
-- Replace combined/bricktracker_parts references with parts_combined for this query
|
||||
ORDER BY {{ order | replace('"combined"', '"parts_combined"') | replace('"bricktracker_parts"', '"parts_combined"') }}
|
||||
{% endif %}
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
{% block where %}
|
||||
WHERE "rebrickable_parts"."print" IS NOT DISTINCT FROM :print
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM :color
|
||||
AND "bricktracker_parts"."part" IS DISTINCT FROM :part
|
||||
AND "combined"."color" IS NOT DISTINCT FROM :color
|
||||
AND "combined"."part" IS DISTINCT FROM :part
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color"
|
||||
"combined"."part",
|
||||
"combined"."color"
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{% extends 'part/base/base.sql' %}
|
||||
|
||||
{% block total_missing %}
|
||||
"bricktracker_parts"."missing" AS "total_missing",
|
||||
"combined"."missing" AS "total_missing",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
"bricktracker_parts"."damaged" AS "total_damaged",
|
||||
"combined"."damaged" AS "total_damaged",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
"bricktracker_parts"."quantity" AS "total_quantity",
|
||||
"combined"."quantity" AS "total_quantity",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_spare %}
|
||||
"bricktracker_parts"."spare" AS "total_spare",
|
||||
"combined"."spare" AS "total_spare",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_sets %}
|
||||
@@ -21,13 +21,13 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block total_minifigures %}
|
||||
CASE WHEN "bricktracker_parts"."figure" IS NOT NULL THEN 1 ELSE 0 END AS "total_minifigures"
|
||||
CASE WHEN "combined"."figure" IS NOT NULL THEN 1 ELSE 0 END AS "total_minifigures"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% set _ = conditions.append('"combined"."spare" = 0') %}
|
||||
{% endif %}
|
||||
{% if conditions %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
|
||||
@@ -2,104 +2,118 @@
|
||||
|
||||
{% block total_missing %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."missing" ELSE 0 END) AS "total_missing",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."missing"
|
||||
WHEN "combined"."source_type" = 'individual' AND "ind_minifig_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."missing"
|
||||
ELSE 0
|
||||
END) AS "total_missing",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."missing") AS "total_missing",
|
||||
SUM("combined"."missing") AS "total_missing",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."damaged" ELSE 0 END) AS "total_damaged",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."damaged"
|
||||
WHEN "combined"."source_type" = 'individual' AND "ind_minifig_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."damaged"
|
||||
ELSE 0
|
||||
END) AS "total_damaged",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."damaged") AS "total_damaged",
|
||||
SUM("combined"."damaged") AS "total_damaged",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1) ELSE 0 END) AS "total_quantity",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)
|
||||
WHEN "combined"."source_type" = 'individual' AND "ind_minifig_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."quantity" * IFNULL("bricktracker_individual_minifigures"."quantity", 1)
|
||||
ELSE 0
|
||||
END) AS "total_quantity",
|
||||
{% else %}
|
||||
SUM("bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)) AS "total_quantity",
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' THEN "combined"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)
|
||||
WHEN "combined"."source_type" = 'individual' THEN "combined"."quantity" * IFNULL("bricktracker_individual_minifigures"."quantity", 1)
|
||||
ELSE "combined"."quantity"
|
||||
END) AS "total_quantity",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_sets %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
COUNT(DISTINCT CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "bricktracker_parts"."id" ELSE NULL END) AS "total_sets",
|
||||
COUNT(DISTINCT CASE WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN "combined"."id" ELSE NULL END) AS "total_sets",
|
||||
{% else %}
|
||||
COUNT(DISTINCT "bricktracker_parts"."id") AS "total_sets",
|
||||
COUNT(DISTINCT CASE WHEN "combined"."source_type" = 'set' THEN "combined"."id" ELSE NULL END) AS "total_sets",
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block total_minifigures %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
SUM(CASE WHEN "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN IFNULL("bricktracker_minifigures"."quantity", 0) ELSE 0 END) AS "total_minifigures"
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' AND "bricktracker_set_owners"."owner_{{ owner_id }}" = 1 THEN IFNULL("bricktracker_minifigures"."quantity", 0)
|
||||
WHEN "combined"."source_type" = 'individual' AND "ind_minifig_owners"."owner_{{ owner_id }}" = 1 THEN IFNULL("bricktracker_individual_minifigures"."quantity", 0)
|
||||
ELSE 0
|
||||
END) AS "total_minifigures"
|
||||
{% else %}
|
||||
SUM(IFNULL("bricktracker_minifigures"."quantity", 0)) AS "total_minifigures"
|
||||
SUM(CASE
|
||||
WHEN "combined"."source_type" = 'set' THEN IFNULL("bricktracker_minifigures"."quantity", 0)
|
||||
WHEN "combined"."source_type" = 'individual' THEN IFNULL("bricktracker_individual_minifigures"."quantity", 0)
|
||||
ELSE 0
|
||||
END) AS "total_minifigures"
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block join %}
|
||||
-- Join with sets to get owner information
|
||||
INNER JOIN "bricktracker_sets"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
|
||||
-- Join with rebrickable sets for theme/year filtering
|
||||
INNER JOIN "rebrickable_sets"
|
||||
ON "bricktracker_sets"."set" IS NOT DISTINCT FROM "rebrickable_sets"."set"
|
||||
-- Left join with sets for set-based parts
|
||||
LEFT JOIN "bricktracker_sets"
|
||||
ON "combined"."source_type" = 'set'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_sets"."id"
|
||||
|
||||
-- Left join with set owners (using dynamic columns)
|
||||
LEFT JOIN "bricktracker_set_owners"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||
|
||||
-- Left join with set tags (for tag filtering)
|
||||
{% if tag_id and tag_id != 'all' %}
|
||||
LEFT JOIN "bricktracker_set_tags"
|
||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_tags"."id"
|
||||
{% endif %}
|
||||
|
||||
-- Left join with minifigures
|
||||
-- Left join with set-based minifigures
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
ON "combined"."source_type" = 'set'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
|
||||
-- Left join with individual minifigures
|
||||
LEFT JOIN "bricktracker_individual_minifigures"
|
||||
ON "combined"."source_type" = 'individual'
|
||||
AND "combined"."id" IS NOT DISTINCT FROM "bricktracker_individual_minifigures"."id"
|
||||
|
||||
-- Left join with individual minifigure owners (using consolidated metadata table)
|
||||
LEFT JOIN "bricktracker_set_owners" AS "ind_minifig_owners"
|
||||
ON "bricktracker_individual_minifigures"."id" IS NOT DISTINCT FROM "ind_minifig_owners"."id"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
-- Always filter for problematic parts
|
||||
{% set _ = conditions.append('("bricktracker_parts"."missing" > 0 OR "bricktracker_parts"."damaged" > 0)') %}
|
||||
{% set _ = conditions.append('("combined"."missing" > 0 OR "combined"."damaged" > 0)') %}
|
||||
{% if owner_id and owner_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_set_owners"."owner_' ~ owner_id ~ '" = 1') %}
|
||||
{% set owner_condition = '(("combined"."source_type" = \'set\' AND "bricktracker_set_owners"."owner_' ~ owner_id ~ '" = 1) OR ("combined"."source_type" = \'individual\' AND "ind_minifig_owners"."owner_' ~ owner_id ~ '" = 1))' %}
|
||||
{% set _ = conditions.append(owner_condition) %}
|
||||
{% endif %}
|
||||
{% if color_id and color_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."color" = ' ~ color_id) %}
|
||||
{% endif %}
|
||||
{% if theme_id and theme_id != 'all' %}
|
||||
{% set _ = conditions.append('"rebrickable_sets"."theme_id" = ' ~ theme_id) %}
|
||||
{% endif %}
|
||||
{% if year and year != 'all' %}
|
||||
{% set _ = conditions.append('"rebrickable_sets"."year" = ' ~ year) %}
|
||||
{% endif %}
|
||||
{% if storage_id and storage_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_sets"."storage" = \'' ~ storage_id ~ '\'') %}
|
||||
{% endif %}
|
||||
{% if tag_id and tag_id != 'all' %}
|
||||
{% set _ = conditions.append('"bricktracker_set_tags"."tag_' ~ tag_id ~ '" = 1') %}
|
||||
{% set _ = conditions.append('"combined"."color" = ' ~ color_id) %}
|
||||
{% endif %}
|
||||
{% if search_query %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("bricktracker_parts"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set search_condition = '(LOWER("rebrickable_parts"."name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("rebrickable_parts"."color_name") LIKE LOWER(\'%' ~ search_query ~ '%\') OR LOWER("combined"."part") LIKE LOWER(\'%' ~ search_query ~ '%\'))' %}
|
||||
{% set _ = conditions.append(search_condition) %}
|
||||
{% endif %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% set _ = conditions.append('"combined"."spare" = 0') %}
|
||||
{% endif %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare"
|
||||
"combined"."part",
|
||||
"combined"."color",
|
||||
"combined"."spare"
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,19 +2,14 @@
|
||||
{% extends 'part/base/base.sql' %}
|
||||
|
||||
{% block total_missing %}
|
||||
IFNULL("bricktracker_parts"."missing", 0) AS "total_missing",
|
||||
IFNULL("combined"."missing", 0) AS "total_missing",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
IFNULL("bricktracker_parts"."damaged", 0) AS "total_damaged",
|
||||
IFNULL("combined"."damaged", 0) AS "total_damaged",
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
{% set conditions = [] %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."id" IS NOT DISTINCT FROM :id') %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."figure" IS NOT DISTINCT FROM :figure') %}
|
||||
{% if skip_spare_parts %}
|
||||
{% set _ = conditions.append('"bricktracker_parts"."spare" = 0') %}
|
||||
{% endif %}
|
||||
WHERE {{ conditions | join(' AND ') }}
|
||||
WHERE "combined"."id" IS NOT DISTINCT FROM :id
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM :figure
|
||||
{% endblock %}
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
{% block total_damaged %}{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
WHERE "bricktracker_parts"."color" IS DISTINCT FROM :color
|
||||
AND "bricktracker_parts"."part" IS NOT DISTINCT FROM :part
|
||||
WHERE "combined"."color" IS DISTINCT FROM :color
|
||||
AND "combined"."part" IS NOT DISTINCT FROM :part
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color"
|
||||
"combined"."part",
|
||||
"combined"."color"
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,34 +1,51 @@
|
||||
{% extends 'part/base/base.sql' %}
|
||||
|
||||
{% block total_missing %}
|
||||
SUM("bricktracker_parts"."missing") AS "total_missing",
|
||||
SUM("combined"."missing") AS "total_missing",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_damaged %}
|
||||
SUM("bricktracker_parts"."damaged") AS "total_damaged",
|
||||
SUM("combined"."damaged") AS "total_damaged",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_quantity %}
|
||||
SUM((NOT "bricktracker_parts"."spare") * "bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)) AS "total_quantity",
|
||||
SUM((NOT "combined"."spare") * "combined"."quantity" * IFNULL("minifigure_quantities"."quantity", 1)) AS "total_quantity",
|
||||
{% endblock %}
|
||||
|
||||
{% block total_spare %}
|
||||
SUM("bricktracker_parts"."spare" * "bricktracker_parts"."quantity" * IFNULL("bricktracker_minifigures"."quantity", 1)) AS "total_spare",
|
||||
SUM("combined"."spare" * "combined"."quantity" * IFNULL("minifigure_quantities"."quantity", 1)) AS "total_spare",
|
||||
{% endblock %}
|
||||
|
||||
{% block join %}
|
||||
LEFT JOIN "bricktracker_minifigures"
|
||||
ON "bricktracker_parts"."id" IS NOT DISTINCT FROM "bricktracker_minifigures"."id"
|
||||
AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM "bricktracker_minifigures"."figure"
|
||||
-- Join to get minifigure quantities from both set-based and individual minifigures
|
||||
LEFT JOIN (
|
||||
-- Set-based minifigure quantities
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
"bricktracker_minifigures"."figure",
|
||||
"bricktracker_minifigures"."quantity"
|
||||
FROM "bricktracker_minifigures"
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Individual minifigure quantities
|
||||
SELECT
|
||||
"bricktracker_individual_minifigures"."id",
|
||||
"bricktracker_individual_minifigures"."figure",
|
||||
"bricktracker_individual_minifigures"."quantity"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
) AS "minifigure_quantities"
|
||||
ON "combined"."id" IS NOT DISTINCT FROM "minifigure_quantities"."id"
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM "minifigure_quantities"."figure"
|
||||
{% endblock %}
|
||||
|
||||
{% block where %}
|
||||
WHERE "bricktracker_parts"."part" IS NOT DISTINCT FROM :part
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM :color
|
||||
WHERE "combined"."part" IS NOT DISTINCT FROM :part
|
||||
AND "combined"."color" IS NOT DISTINCT FROM :color
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color"
|
||||
"combined"."part",
|
||||
"combined"."color"
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{% extends 'part/base/base.sql' %}
|
||||
|
||||
{% block where %}
|
||||
WHERE "bricktracker_parts"."id" IS NOT DISTINCT FROM :id
|
||||
AND "bricktracker_parts"."figure" IS NOT DISTINCT FROM :figure
|
||||
AND "bricktracker_parts"."part" IS NOT DISTINCT FROM :part
|
||||
AND "bricktracker_parts"."color" IS NOT DISTINCT FROM :color
|
||||
AND "bricktracker_parts"."spare" IS NOT DISTINCT FROM :spare
|
||||
WHERE "combined"."id" IS NOT DISTINCT FROM :id
|
||||
AND "combined"."figure" IS NOT DISTINCT FROM :figure
|
||||
AND "combined"."part" IS NOT DISTINCT FROM :part
|
||||
AND "combined"."color" IS NOT DISTINCT FROM :color
|
||||
AND "combined"."spare" IS NOT DISTINCT FROM :spare
|
||||
{% endblock %}
|
||||
|
||||
{% block group %}
|
||||
GROUP BY
|
||||
"bricktracker_parts"."id",
|
||||
"bricktracker_parts"."figure",
|
||||
"bricktracker_parts"."part",
|
||||
"bricktracker_parts"."color",
|
||||
"bricktracker_parts"."spare"
|
||||
"combined"."id",
|
||||
"combined"."figure",
|
||||
"combined"."part",
|
||||
"combined"."color",
|
||||
"combined"."spare"
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,31 +1,70 @@
|
||||
BEGIN transaction;
|
||||
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_owners";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_statuses";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_tags";
|
||||
-- Disable foreign key checks during drop to avoid constraint errors
|
||||
PRAGMA foreign_keys = OFF;
|
||||
|
||||
-- Drop child tables first (those with foreign key references)
|
||||
|
||||
-- Individual minifigure parts (references individual_minifigures)
|
||||
DROP TABLE IF EXISTS "bricktracker_individual_minifigure_parts";
|
||||
|
||||
-- Individual parts (references individual_part_lots)
|
||||
-- Drop before lots since lot_id is a foreign key
|
||||
DROP TABLE IF EXISTS "bricktracker_individual_parts";
|
||||
|
||||
-- Individual minifigures (references rebrickable_minifigures, metadata tables)
|
||||
DROP TABLE IF EXISTS "bricktracker_individual_minifigures";
|
||||
|
||||
-- Individual part lots (references metadata tables)
|
||||
DROP TABLE IF EXISTS "bricktracker_individual_part_lots";
|
||||
|
||||
-- Set-based parts and minifigures (references sets)
|
||||
DROP TABLE IF EXISTS "bricktracker_minifigures";
|
||||
DROP TABLE IF EXISTS "bricktracker_parts";
|
||||
DROP TABLE IF EXISTS "bricktracker_sets";
|
||||
|
||||
-- Set metadata junction tables (reference sets and metadata)
|
||||
DROP TABLE IF EXISTS "bricktracker_set_checkboxes";
|
||||
DROP TABLE IF EXISTS "bricktracker_set_owners";
|
||||
DROP TABLE IF EXISTS "bricktracker_set_statuses";
|
||||
DROP TABLE IF EXISTS "bricktracker_set_storages";
|
||||
DROP TABLE IF EXISTS "bricktracker_set_tags";
|
||||
|
||||
-- Wish metadata junction tables
|
||||
DROP TABLE IF EXISTS "bricktracker_wish_owners";
|
||||
|
||||
-- Main sets and wishes tables
|
||||
DROP TABLE IF EXISTS "bricktracker_sets";
|
||||
DROP TABLE IF EXISTS "bricktracker_wishes";
|
||||
|
||||
-- Metadata definition tables
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_owners";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_statuses";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_tags";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_storages";
|
||||
DROP TABLE IF EXISTS "bricktracker_metadata_purchase_locations";
|
||||
|
||||
-- Rebrickable reference tables
|
||||
DROP TABLE IF EXISTS "rebrickable_colors";
|
||||
DROP TABLE IF EXISTS "rebrickable_minifigures";
|
||||
DROP TABLE IF EXISTS "rebrickable_parts";
|
||||
DROP TABLE IF EXISTS "rebrickable_sets";
|
||||
DROP TABLE IF EXISTS "rebrickable_sets_new";
|
||||
|
||||
-- Legacy/migration tables
|
||||
DROP TABLE IF EXISTS "inventory";
|
||||
DROP TABLE IF EXISTS "inventory_old";
|
||||
DROP TABLE IF EXISTS "minifigures";
|
||||
DROP TABLE IF EXISTS "minifigures_old";
|
||||
DROP TABLE IF EXISTS "missing";
|
||||
DROP TABLE IF EXISTS "missing_old";
|
||||
DROP TABLE IF EXISTS "rebrickable_minifigures";
|
||||
DROP TABLE IF EXISTS "rebrickable_parts";
|
||||
DROP TABLE IF EXISTS "rebrickable_sets";
|
||||
DROP TABLE IF EXISTS "sets";
|
||||
DROP TABLE IF EXISTS "sets_old";
|
||||
DROP TABLE IF EXISTS "wishlist";
|
||||
DROP TABLE IF EXISTS "wishlist_old";
|
||||
|
||||
-- Re-enable foreign key checks
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA user_version = 0;
|
||||
@@ -1,9 +1,10 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
-- Add owner column to set_owners table (used by all entities: sets, individual parts, individual minifigures, individual part lots)
|
||||
ALTER TABLE "bricktracker_set_owners"
|
||||
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
||||
-- Also inject into wishes
|
||||
-- Also inject into wishes (wishes use their own table)
|
||||
ALTER TABLE "bricktracker_wish_owners"
|
||||
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
SELECT
|
||||
"bricktracker_metadata_purchase_locations"."id",
|
||||
"bricktracker_metadata_purchase_locations"."name"
|
||||
"bricktracker_metadata_purchase_locations"."name",
|
||||
{% block total_sets %}
|
||||
NULL as "total_sets" -- dummy for order: total_sets
|
||||
{% endblock %}
|
||||
FROM "bricktracker_metadata_purchase_locations"
|
||||
|
||||
{% block join %}{% endblock %}
|
||||
|
||||
{% block where %}{% endblock %}
|
||||
|
||||
{% block group %}{% endblock %}
|
||||
|
||||
{% if order %}
|
||||
ORDER BY {{ order }}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
-- Add status column to set_statuses table (used by all entities: sets, individual parts, individual minifigures)
|
||||
-- Note: Individual part lots don't have statuses
|
||||
ALTER TABLE "bricktracker_set_statuses"
|
||||
ADD COLUMN "status_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
-- Add tag column to set_tags table (used by all entities: sets, individual parts, individual minifigures, individual part lots)
|
||||
ALTER TABLE "bricktracker_set_tags"
|
||||
ADD COLUMN "tag_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
-- Statistics Overview Query (Optimized with CTEs)
|
||||
-- Provides comprehensive statistics for BrickTracker dashboard
|
||||
-- Performance improved by consolidating subqueries into CTEs
|
||||
-- Expected impact: 60-80% performance improvement for dashboard loading
|
||||
-- Statistics Overview Query
|
||||
-- Provides statistics for BrickTracker dashboard
|
||||
|
||||
WITH
|
||||
-- Set statistics aggregation
|
||||
@@ -21,31 +19,147 @@ set_stats AS (
|
||||
FROM "bricktracker_sets"
|
||||
),
|
||||
|
||||
-- Part statistics aggregation
|
||||
part_stats AS (
|
||||
-- Part statistics aggregation (set-based parts)
|
||||
set_part_stats AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_part_instances,
|
||||
SUM("quantity") AS total_parts_count,
|
||||
COALESCE(SUM("quantity"), 0) AS total_parts_count,
|
||||
COUNT(DISTINCT "part") AS unique_parts,
|
||||
SUM("missing") AS total_missing_parts,
|
||||
SUM("damaged") AS total_damaged_parts
|
||||
COALESCE(SUM("missing"), 0) AS total_missing_parts,
|
||||
COALESCE(SUM("damaged"), 0) AS total_damaged_parts
|
||||
FROM "bricktracker_parts"
|
||||
),
|
||||
|
||||
-- Minifigure statistics aggregation
|
||||
minifig_stats AS (
|
||||
-- Individual part statistics aggregation
|
||||
individual_part_stats AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_individual_parts,
|
||||
COALESCE(SUM("quantity"), 0) AS total_individual_parts_count,
|
||||
COUNT(DISTINCT "part") AS unique_individual_parts,
|
||||
COALESCE(SUM("missing"), 0) AS total_missing_individual_parts,
|
||||
COALESCE(SUM("damaged"), 0) AS total_damaged_individual_parts,
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL AND "lot_id" IS NULL THEN 1 END) AS individual_parts_with_price,
|
||||
COALESCE(ROUND(SUM(CASE WHEN "lot_id" IS NULL THEN "purchase_price" END), 2), 0) AS individual_parts_total_cost
|
||||
FROM "bricktracker_individual_parts"
|
||||
),
|
||||
|
||||
-- Combined part statistics
|
||||
part_stats AS (
|
||||
SELECT
|
||||
set_part_stats.total_part_instances + COALESCE(individual_part_stats.total_individual_parts, 0) AS total_part_instances,
|
||||
set_part_stats.total_parts_count + COALESCE(individual_part_stats.total_individual_parts_count, 0) AS total_parts_count,
|
||||
(SELECT COUNT(DISTINCT "part") FROM (
|
||||
SELECT "part" FROM "bricktracker_parts"
|
||||
UNION
|
||||
SELECT "part" FROM "bricktracker_individual_parts"
|
||||
)) AS unique_parts,
|
||||
set_part_stats.total_missing_parts + COALESCE(individual_part_stats.total_missing_individual_parts, 0) AS total_missing_parts,
|
||||
set_part_stats.total_damaged_parts + COALESCE(individual_part_stats.total_damaged_individual_parts, 0) AS total_damaged_parts
|
||||
FROM set_part_stats, individual_part_stats
|
||||
),
|
||||
|
||||
-- Minifigure statistics aggregation (set-based minifigures)
|
||||
set_minifig_stats AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_minifigure_instances,
|
||||
SUM("quantity") AS total_minifigures_count,
|
||||
COALESCE(SUM("quantity"), 0) AS total_minifigures_count,
|
||||
COUNT(DISTINCT "figure") AS unique_minifigures
|
||||
FROM "bricktracker_minifigures"
|
||||
),
|
||||
|
||||
-- Individual minifigure statistics aggregation
|
||||
individual_minifig_stats AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_individual_minifigures,
|
||||
COALESCE(SUM("quantity"), 0) AS total_individual_minifigures_count,
|
||||
COUNT(DISTINCT "figure") AS unique_individual_minifigures,
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS individual_minifigs_with_price,
|
||||
COALESCE(ROUND(SUM("purchase_price"), 2), 0) AS individual_minifigs_total_cost
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
),
|
||||
|
||||
-- Combined minifigure statistics
|
||||
minifig_stats AS (
|
||||
SELECT
|
||||
set_minifig_stats.total_minifigure_instances + COALESCE(individual_minifig_stats.total_individual_minifigures, 0) AS total_minifigure_instances,
|
||||
set_minifig_stats.total_minifigures_count + COALESCE(individual_minifig_stats.total_individual_minifigures_count, 0) AS total_minifigures_count,
|
||||
(SELECT COUNT(DISTINCT "figure") FROM (
|
||||
SELECT "figure" FROM "bricktracker_minifigures"
|
||||
UNION
|
||||
SELECT "figure" FROM "bricktracker_individual_minifigures"
|
||||
)) AS unique_minifigures
|
||||
FROM set_minifig_stats, individual_minifig_stats
|
||||
),
|
||||
|
||||
-- Part lot statistics aggregation
|
||||
part_lot_stats AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_part_lots,
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS part_lots_with_price,
|
||||
ROUND(SUM("purchase_price"), 2) AS part_lots_total_cost
|
||||
FROM "bricktracker_individual_part_lots"
|
||||
),
|
||||
|
||||
-- Rebrickable sets count (for sets we actually own)
|
||||
rebrickable_stats AS (
|
||||
SELECT COUNT(*) AS unique_rebrickable_sets
|
||||
FROM "rebrickable_sets"
|
||||
WHERE "set" IN (SELECT DISTINCT "set" FROM "bricktracker_sets")
|
||||
),
|
||||
|
||||
-- Combined financial statistics
|
||||
financial_stats AS (
|
||||
SELECT
|
||||
-- Items with price
|
||||
set_stats.sets_with_price +
|
||||
COALESCE(individual_part_stats.individual_parts_with_price, 0) +
|
||||
COALESCE(individual_minifig_stats.individual_minifigs_with_price, 0) +
|
||||
COALESCE(part_lot_stats.part_lots_with_price, 0) AS total_items_with_price,
|
||||
|
||||
-- Total cost across all item types
|
||||
ROUND(COALESCE(set_stats.total_cost, 0) +
|
||||
COALESCE(individual_part_stats.individual_parts_total_cost, 0) +
|
||||
COALESCE(individual_minifig_stats.individual_minifigs_total_cost, 0) +
|
||||
COALESCE(part_lot_stats.part_lots_total_cost, 0), 2) AS combined_total_cost,
|
||||
|
||||
-- Average cost across all items with price
|
||||
CASE
|
||||
WHEN (set_stats.sets_with_price +
|
||||
COALESCE(individual_part_stats.individual_parts_with_price, 0) +
|
||||
COALESCE(individual_minifig_stats.individual_minifigs_with_price, 0) +
|
||||
COALESCE(part_lot_stats.part_lots_with_price, 0)) > 0
|
||||
THEN ROUND((COALESCE(set_stats.total_cost, 0) +
|
||||
COALESCE(individual_part_stats.individual_parts_total_cost, 0) +
|
||||
COALESCE(individual_minifig_stats.individual_minifigs_total_cost, 0) +
|
||||
COALESCE(part_lot_stats.part_lots_total_cost, 0)) /
|
||||
(set_stats.sets_with_price +
|
||||
COALESCE(individual_part_stats.individual_parts_with_price, 0) +
|
||||
COALESCE(individual_minifig_stats.individual_minifigs_with_price, 0) +
|
||||
COALESCE(part_lot_stats.part_lots_with_price, 0)), 2)
|
||||
ELSE 0
|
||||
END AS combined_average_cost,
|
||||
|
||||
-- Min/Max price across all item types
|
||||
(SELECT MIN(price) FROM (
|
||||
SELECT "purchase_price" AS price FROM "bricktracker_sets" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_parts" WHERE "purchase_price" IS NOT NULL AND "lot_id" IS NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_minifigures" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_part_lots" WHERE "purchase_price" IS NOT NULL
|
||||
)) AS combined_minimum_cost,
|
||||
|
||||
(SELECT MAX(price) FROM (
|
||||
SELECT "purchase_price" AS price FROM "bricktracker_sets" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_parts" WHERE "purchase_price" IS NOT NULL AND "lot_id" IS NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_minifigures" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_part_lots" WHERE "purchase_price" IS NOT NULL
|
||||
)) AS combined_maximum_cost
|
||||
FROM set_stats, individual_part_stats, individual_minifig_stats, part_lot_stats
|
||||
)
|
||||
|
||||
-- Final select combining all statistics
|
||||
@@ -67,17 +181,24 @@ SELECT
|
||||
minifig_stats.total_minifigures_count,
|
||||
minifig_stats.unique_minifigures,
|
||||
|
||||
-- Financial statistics
|
||||
-- Financial statistics (set-only for backwards compatibility)
|
||||
set_stats.sets_with_price,
|
||||
set_stats.total_cost,
|
||||
set_stats.average_cost,
|
||||
set_stats.minimum_cost,
|
||||
set_stats.maximum_cost,
|
||||
|
||||
-- Combined financial statistics (all item types)
|
||||
financial_stats.total_items_with_price,
|
||||
financial_stats.combined_total_cost,
|
||||
financial_stats.combined_average_cost,
|
||||
financial_stats.combined_minimum_cost,
|
||||
financial_stats.combined_maximum_cost,
|
||||
|
||||
-- Storage and location statistics
|
||||
set_stats.storage_locations_used,
|
||||
set_stats.purchase_locations_used,
|
||||
set_stats.sets_with_storage,
|
||||
set_stats.sets_with_purchase_location
|
||||
|
||||
FROM set_stats, part_stats, minifig_stats, rebrickable_stats
|
||||
FROM set_stats, part_stats, minifig_stats, rebrickable_stats, financial_stats
|
||||
@@ -1,45 +1,174 @@
|
||||
-- Purchase Location Statistics
|
||||
-- Shows statistics grouped by purchase location
|
||||
-- Includes sets, individual parts, individual minifigures, and part lots
|
||||
|
||||
WITH
|
||||
|
||||
-- Set statistics by purchase location
|
||||
set_purchase_stats AS (
|
||||
SELECT
|
||||
"bricktracker_sets"."purchase_location" AS "location_id",
|
||||
COUNT("bricktracker_sets"."id") AS "set_count",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_set_count",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "total_spent",
|
||||
MIN("bricktracker_sets"."purchase_date") AS "first_purchase",
|
||||
MAX("bricktracker_sets"."purchase_date") AS "latest_purchase",
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "damaged_parts",
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "total_minifigures"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."purchase_location" IS NOT NULL
|
||||
GROUP BY "bricktracker_sets"."purchase_location"
|
||||
),
|
||||
|
||||
-- Individual part statistics by purchase location
|
||||
individual_part_purchase_stats AS (
|
||||
SELECT
|
||||
"purchase_location" AS "location_id",
|
||||
COUNT(*) AS "individual_part_count",
|
||||
SUM("quantity") AS "individual_part_quantity",
|
||||
SUM("missing") AS "individual_missing_parts",
|
||||
SUM("damaged") AS "individual_damaged_parts",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "individual_parts_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "individual_total_spent",
|
||||
MIN("purchase_date") AS "individual_first_purchase",
|
||||
MAX("purchase_date") AS "individual_latest_purchase"
|
||||
FROM "bricktracker_individual_parts"
|
||||
WHERE "purchase_location" IS NOT NULL AND "lot_id" IS NULL
|
||||
GROUP BY "purchase_location"
|
||||
),
|
||||
|
||||
-- Individual minifigure statistics by purchase location
|
||||
individual_minifig_purchase_stats AS (
|
||||
SELECT
|
||||
"purchase_location" AS "location_id",
|
||||
COUNT(*) AS "individual_minifig_count",
|
||||
SUM("quantity") AS "individual_minifig_quantity",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "individual_minifigs_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "individual_minifig_total_spent",
|
||||
MIN("purchase_date") AS "individual_minifig_first_purchase",
|
||||
MAX("purchase_date") AS "individual_minifig_latest_purchase"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
WHERE "purchase_location" IS NOT NULL
|
||||
GROUP BY "purchase_location"
|
||||
),
|
||||
|
||||
-- Part lot statistics by purchase location
|
||||
part_lot_purchase_stats AS (
|
||||
SELECT
|
||||
"purchase_location" AS "location_id",
|
||||
COUNT(*) AS "lot_count",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "lots_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "lot_total_spent",
|
||||
MIN("purchase_date") AS "lot_first_purchase",
|
||||
MAX("purchase_date") AS "lot_latest_purchase"
|
||||
FROM "bricktracker_individual_part_lots"
|
||||
WHERE "purchase_location" IS NOT NULL
|
||||
GROUP BY "purchase_location"
|
||||
),
|
||||
|
||||
-- Min/Max price calculations (across all item types)
|
||||
price_stats AS (
|
||||
SELECT
|
||||
"purchase_location" AS "location_id",
|
||||
MIN("purchase_price") AS "min_price",
|
||||
MAX("purchase_price") AS "max_price"
|
||||
FROM (
|
||||
SELECT "purchase_location", "purchase_price" FROM "bricktracker_sets" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_location", "purchase_price" FROM "bricktracker_individual_parts" WHERE "purchase_price" IS NOT NULL AND "lot_id" IS NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_location", "purchase_price" FROM "bricktracker_individual_minifigures" WHERE "purchase_price" IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT "purchase_location", "purchase_price" FROM "bricktracker_individual_part_lots" WHERE "purchase_price" IS NOT NULL
|
||||
)
|
||||
WHERE "purchase_location" IS NOT NULL
|
||||
GROUP BY "purchase_location"
|
||||
)
|
||||
|
||||
-- Combine all statistics
|
||||
SELECT
|
||||
"bricktracker_sets"."purchase_location" AS "location_id",
|
||||
COALESCE(sps.location_id, ipps.location_id, imps.location_id, plps.location_id) AS "location_id",
|
||||
"bricktracker_metadata_purchase_locations"."name" AS "location_name",
|
||||
COUNT("bricktracker_sets"."id") AS "set_count",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_set_count",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
ROUND(AVG("rebrickable_sets"."number_of_parts"), 0) AS "avg_parts_per_set",
|
||||
-- Financial statistics per purchase location
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "total_spent",
|
||||
ROUND(AVG("bricktracker_sets"."purchase_price"), 2) AS "avg_price",
|
||||
ROUND(MIN("bricktracker_sets"."purchase_price"), 2) AS "min_price",
|
||||
ROUND(MAX("bricktracker_sets"."purchase_price"), 2) AS "max_price",
|
||||
-- Date range statistics
|
||||
MIN("bricktracker_sets"."purchase_date") AS "first_purchase",
|
||||
MAX("bricktracker_sets"."purchase_date") AS "latest_purchase",
|
||||
-- Problem statistics per purchase location
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "damaged_parts",
|
||||
-- Minifigure statistics per purchase location
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "total_minifigures"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN "bricktracker_metadata_purchase_locations" ON "bricktracker_sets"."purchase_location" = "bricktracker_metadata_purchase_locations"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."purchase_location" IS NOT NULL
|
||||
GROUP BY "bricktracker_sets"."purchase_location", "bricktracker_metadata_purchase_locations"."name"
|
||||
ORDER BY "set_count" DESC, "location_name" ASC
|
||||
|
||||
-- Set counts
|
||||
COALESCE(sps.set_count, 0) AS "set_count",
|
||||
COALESCE(sps.unique_set_count, 0) AS "unique_set_count",
|
||||
|
||||
-- Individual item counts
|
||||
COALESCE(ipps.individual_part_count, 0) AS "individual_part_count",
|
||||
COALESCE(imps.individual_minifig_count, 0) AS "individual_minifig_count",
|
||||
COALESCE(plps.lot_count, 0) AS "lot_count",
|
||||
|
||||
-- Part counts
|
||||
COALESCE(sps.total_parts, 0) + COALESCE(ipps.individual_part_quantity, 0) AS "total_parts",
|
||||
CASE
|
||||
WHEN COALESCE(sps.set_count, 0) > 0
|
||||
THEN ROUND(CAST(COALESCE(sps.total_parts, 0) AS FLOAT) / sps.set_count, 0)
|
||||
ELSE 0
|
||||
END AS "avg_parts_per_set",
|
||||
|
||||
-- Financial statistics
|
||||
COALESCE(sps.sets_with_price, 0) + COALESCE(ipps.individual_parts_with_price, 0) +
|
||||
COALESCE(imps.individual_minifigs_with_price, 0) + COALESCE(plps.lots_with_price, 0) AS "items_with_price",
|
||||
ROUND(COALESCE(sps.total_spent, 0) + COALESCE(ipps.individual_total_spent, 0) +
|
||||
COALESCE(imps.individual_minifig_total_spent, 0) + COALESCE(plps.lot_total_spent, 0), 2) AS "total_spent",
|
||||
CASE
|
||||
WHEN (COALESCE(sps.sets_with_price, 0) + COALESCE(ipps.individual_parts_with_price, 0) +
|
||||
COALESCE(imps.individual_minifigs_with_price, 0) + COALESCE(plps.lots_with_price, 0)) > 0
|
||||
THEN ROUND((COALESCE(sps.total_spent, 0) + COALESCE(ipps.individual_total_spent, 0) +
|
||||
COALESCE(imps.individual_minifig_total_spent, 0) + COALESCE(plps.lot_total_spent, 0)) /
|
||||
(COALESCE(sps.sets_with_price, 0) + COALESCE(ipps.individual_parts_with_price, 0) +
|
||||
COALESCE(imps.individual_minifigs_with_price, 0) + COALESCE(plps.lots_with_price, 0)), 2)
|
||||
ELSE 0
|
||||
END AS "avg_price",
|
||||
ROUND(COALESCE(ps.min_price, 0), 2) AS "min_price",
|
||||
ROUND(COALESCE(ps.max_price, 0), 2) AS "max_price",
|
||||
|
||||
-- Date range statistics (earliest and latest purchases across all types)
|
||||
(SELECT MIN(d) FROM (
|
||||
SELECT sps.first_purchase AS d
|
||||
UNION ALL SELECT ipps.individual_first_purchase
|
||||
UNION ALL SELECT imps.individual_minifig_first_purchase
|
||||
UNION ALL SELECT plps.lot_first_purchase
|
||||
) WHERE d IS NOT NULL) AS "first_purchase",
|
||||
(SELECT MAX(d) FROM (
|
||||
SELECT sps.latest_purchase AS d
|
||||
UNION ALL SELECT ipps.individual_latest_purchase
|
||||
UNION ALL SELECT imps.individual_minifig_latest_purchase
|
||||
UNION ALL SELECT plps.lot_latest_purchase
|
||||
) WHERE d IS NOT NULL) AS "latest_purchase",
|
||||
|
||||
-- Problem statistics
|
||||
COALESCE(sps.missing_parts, 0) + COALESCE(ipps.individual_missing_parts, 0) AS "missing_parts",
|
||||
COALESCE(sps.damaged_parts, 0) + COALESCE(ipps.individual_damaged_parts, 0) AS "damaged_parts",
|
||||
|
||||
-- Minifigure counts
|
||||
COALESCE(sps.total_minifigures, 0) + COALESCE(imps.individual_minifig_quantity, 0) AS "total_minifigures"
|
||||
|
||||
FROM set_purchase_stats sps
|
||||
FULL OUTER JOIN individual_part_purchase_stats ipps ON sps.location_id = ipps.location_id
|
||||
FULL OUTER JOIN individual_minifig_purchase_stats imps ON COALESCE(sps.location_id, ipps.location_id) = imps.location_id
|
||||
FULL OUTER JOIN part_lot_purchase_stats plps ON COALESCE(sps.location_id, ipps.location_id, imps.location_id) = plps.location_id
|
||||
LEFT JOIN price_stats ps ON COALESCE(sps.location_id, ipps.location_id, imps.location_id, plps.location_id) = ps.location_id
|
||||
LEFT JOIN "bricktracker_metadata_purchase_locations" ON COALESCE(sps.location_id, ipps.location_id, imps.location_id, plps.location_id) = "bricktracker_metadata_purchase_locations"."id"
|
||||
|
||||
ORDER BY "set_count" DESC, "location_name" ASC
|
||||
|
||||
@@ -1,49 +1,220 @@
|
||||
-- Purchases by Year Statistics
|
||||
-- Shows statistics grouped by purchase year (when you bought the sets)
|
||||
-- Shows statistics grouped by purchase year (when you bought items)
|
||||
-- Includes sets, individual parts, individual minifigures, and part lots
|
||||
|
||||
WITH
|
||||
|
||||
-- Set purchases by year
|
||||
set_purchases AS (
|
||||
SELECT
|
||||
strftime('%Y', datetime("bricktracker_sets"."purchase_date", 'unixepoch')) AS "purchase_year",
|
||||
COUNT("bricktracker_sets"."id") AS "total_sets",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_sets",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
ROUND(AVG("rebrickable_sets"."number_of_parts"), 0) AS "avg_parts_per_set",
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "sets_total_spent",
|
||||
MIN("rebrickable_sets"."year") AS "oldest_set_year",
|
||||
MAX("rebrickable_sets"."year") AS "newest_set_year",
|
||||
ROUND(AVG("rebrickable_sets"."year"), 0) AS "avg_set_release_year",
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "set_missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "set_damaged_parts",
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "set_minifigures",
|
||||
COALESCE(SUM("minifigure_stats"."unique_minifigures"), 0) AS "set_unique_minifigures",
|
||||
COUNT(DISTINCT "rebrickable_sets"."theme_id") AS "unique_themes",
|
||||
COUNT(DISTINCT "bricktracker_sets"."purchase_location") AS "set_unique_purchase_locations",
|
||||
COUNT(DISTINCT strftime('%m', datetime("bricktracker_sets"."purchase_date", 'unixepoch'))) AS "months_with_purchases"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count",
|
||||
COUNT(DISTINCT "bricktracker_minifigures"."figure") AS "unique_minifigures"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."purchase_date" IS NOT NULL
|
||||
GROUP BY strftime('%Y', datetime("bricktracker_sets"."purchase_date", 'unixepoch'))
|
||||
),
|
||||
|
||||
-- Individual part purchases by year
|
||||
individual_part_purchases AS (
|
||||
SELECT
|
||||
strftime('%Y', datetime("bricktracker_individual_parts"."purchase_date", 'unixepoch')) AS "purchase_year",
|
||||
COUNT(*) AS "individual_part_count",
|
||||
SUM("bricktracker_individual_parts"."quantity") AS "individual_part_quantity",
|
||||
COUNT(DISTINCT "bricktracker_individual_parts"."part" || '-' || "bricktracker_individual_parts"."color") AS "unique_individual_parts",
|
||||
SUM("bricktracker_individual_parts"."missing") AS "individual_missing_parts",
|
||||
SUM("bricktracker_individual_parts"."damaged") AS "individual_damaged_parts",
|
||||
COUNT(CASE WHEN "bricktracker_individual_parts"."purchase_price" IS NOT NULL AND "bricktracker_individual_parts"."lot_id" IS NULL THEN 1 END) AS "individual_parts_with_price",
|
||||
ROUND(SUM(CASE WHEN "bricktracker_individual_parts"."lot_id" IS NULL THEN "bricktracker_individual_parts"."purchase_price" END), 2) AS "individual_parts_total_spent",
|
||||
COUNT(DISTINCT "bricktracker_individual_parts"."purchase_location") AS "individual_part_unique_purchase_locations"
|
||||
FROM "bricktracker_individual_parts"
|
||||
WHERE "bricktracker_individual_parts"."purchase_date" IS NOT NULL
|
||||
GROUP BY strftime('%Y', datetime("bricktracker_individual_parts"."purchase_date", 'unixepoch'))
|
||||
),
|
||||
|
||||
-- Individual minifigure purchases by year
|
||||
individual_minifig_purchases AS (
|
||||
SELECT
|
||||
strftime('%Y', datetime("bricktracker_individual_minifigures"."purchase_date", 'unixepoch')) AS "purchase_year",
|
||||
COUNT(*) AS "individual_minifig_count",
|
||||
SUM("bricktracker_individual_minifigures"."quantity") AS "individual_minifig_quantity",
|
||||
COUNT(DISTINCT "bricktracker_individual_minifigures"."figure") AS "unique_individual_minifigures",
|
||||
COUNT(CASE WHEN "bricktracker_individual_minifigures"."purchase_price" IS NOT NULL THEN 1 END) AS "individual_minifigs_with_price",
|
||||
ROUND(SUM("bricktracker_individual_minifigures"."purchase_price"), 2) AS "individual_minifigs_total_spent",
|
||||
COUNT(DISTINCT "bricktracker_individual_minifigures"."purchase_location") AS "individual_minifig_unique_purchase_locations"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
WHERE "bricktracker_individual_minifigures"."purchase_date" IS NOT NULL
|
||||
GROUP BY strftime('%Y', datetime("bricktracker_individual_minifigures"."purchase_date", 'unixepoch'))
|
||||
),
|
||||
|
||||
-- Part lot purchases by year
|
||||
part_lot_purchases AS (
|
||||
SELECT
|
||||
strftime('%Y', datetime("bricktracker_individual_part_lots"."purchase_date", 'unixepoch')) AS "purchase_year",
|
||||
COUNT(*) AS "lot_count",
|
||||
COUNT(CASE WHEN "bricktracker_individual_part_lots"."purchase_price" IS NOT NULL THEN 1 END) AS "lots_with_price",
|
||||
ROUND(SUM("bricktracker_individual_part_lots"."purchase_price"), 2) AS "lots_total_spent",
|
||||
COUNT(DISTINCT "bricktracker_individual_part_lots"."purchase_location") AS "lot_unique_purchase_locations"
|
||||
FROM "bricktracker_individual_part_lots"
|
||||
WHERE "bricktracker_individual_part_lots"."purchase_date" IS NOT NULL
|
||||
GROUP BY strftime('%Y', datetime("bricktracker_individual_part_lots"."purchase_date", 'unixepoch'))
|
||||
),
|
||||
|
||||
-- All purchase years (union of all types)
|
||||
all_years AS (
|
||||
SELECT DISTINCT "purchase_year" FROM set_purchases WHERE "purchase_year" IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT "purchase_year" FROM individual_part_purchases WHERE "purchase_year" IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT "purchase_year" FROM individual_minifig_purchases WHERE "purchase_year" IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT "purchase_year" FROM part_lot_purchases WHERE "purchase_year" IS NOT NULL
|
||||
)
|
||||
|
||||
-- Combine all statistics
|
||||
SELECT
|
||||
strftime('%Y', datetime("bricktracker_sets"."purchase_date", 'unixepoch')) AS "purchase_year",
|
||||
COUNT("bricktracker_sets"."id") AS "total_sets",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_sets",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
ROUND(AVG("rebrickable_sets"."number_of_parts"), 0) AS "avg_parts_per_set",
|
||||
-- Financial statistics per purchase year
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "total_spent",
|
||||
ROUND(AVG("bricktracker_sets"."purchase_price"), 2) AS "avg_price_per_set",
|
||||
ROUND(MIN("bricktracker_sets"."purchase_price"), 2) AS "min_price",
|
||||
ROUND(MAX("bricktracker_sets"."purchase_price"), 2) AS "max_price",
|
||||
-- Release year statistics for sets purchased in this year
|
||||
MIN("rebrickable_sets"."year") AS "oldest_set_year",
|
||||
MAX("rebrickable_sets"."year") AS "newest_set_year",
|
||||
ROUND(AVG("rebrickable_sets"."year"), 0) AS "avg_set_release_year",
|
||||
-- Problem statistics per purchase year
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "damaged_parts",
|
||||
-- Minifigure statistics per purchase year
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "total_minifigures",
|
||||
-- Diversity statistics per purchase year
|
||||
COUNT(DISTINCT "rebrickable_sets"."theme_id") AS "unique_themes",
|
||||
COUNT(DISTINCT "bricktracker_sets"."purchase_location") AS "unique_purchase_locations",
|
||||
-- Monthly statistics within the year
|
||||
COUNT(DISTINCT strftime('%m', datetime("bricktracker_sets"."purchase_date", 'unixepoch'))) AS "months_with_purchases"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."purchase_date" IS NOT NULL
|
||||
GROUP BY strftime('%Y', datetime("bricktracker_sets"."purchase_date", 'unixepoch'))
|
||||
ORDER BY "purchase_year" DESC
|
||||
ay.purchase_year,
|
||||
|
||||
-- Set counts
|
||||
COALESCE(sp.total_sets, 0) AS "total_sets",
|
||||
COALESCE(sp.unique_sets, 0) AS "unique_sets",
|
||||
|
||||
-- Individual item counts
|
||||
COALESCE(ipp.individual_part_count, 0) AS "individual_part_count",
|
||||
COALESCE(imp.individual_minifig_count, 0) AS "individual_minifig_count",
|
||||
COALESCE(plp.lot_count, 0) AS "lot_count",
|
||||
|
||||
-- Part counts (unique and total)
|
||||
COALESCE(ipp.unique_individual_parts, 0) AS "unique_parts",
|
||||
COALESCE(sp.total_parts, 0) + COALESCE(ipp.individual_part_quantity, 0) AS "total_parts",
|
||||
COALESCE(sp.avg_parts_per_set, 0) AS "avg_parts_per_set",
|
||||
|
||||
-- Minifigure counts (unique and total)
|
||||
COALESCE(sp.set_unique_minifigures, 0) + COALESCE(imp.unique_individual_minifigures, 0) AS "unique_minifigures",
|
||||
COALESCE(sp.set_minifigures, 0) + COALESCE(imp.individual_minifig_quantity, 0) AS "total_minifigures",
|
||||
|
||||
-- Financial statistics (combined)
|
||||
COALESCE(sp.sets_with_price, 0) + COALESCE(ipp.individual_parts_with_price, 0) +
|
||||
COALESCE(imp.individual_minifigs_with_price, 0) + COALESCE(plp.lots_with_price, 0) AS "items_with_price",
|
||||
ROUND(COALESCE(sp.sets_total_spent, 0) + COALESCE(ipp.individual_parts_total_spent, 0) +
|
||||
COALESCE(imp.individual_minifigs_total_spent, 0) + COALESCE(plp.lots_total_spent, 0), 2) AS "total_spent",
|
||||
|
||||
-- Average, min, max price across all item types for this year
|
||||
CASE
|
||||
WHEN (COALESCE(sp.sets_with_price, 0) + COALESCE(ipp.individual_parts_with_price, 0) +
|
||||
COALESCE(imp.individual_minifigs_with_price, 0) + COALESCE(plp.lots_with_price, 0)) > 0
|
||||
THEN ROUND((COALESCE(sp.sets_total_spent, 0) + COALESCE(ipp.individual_parts_total_spent, 0) +
|
||||
COALESCE(imp.individual_minifigs_total_spent, 0) + COALESCE(plp.lots_total_spent, 0)) /
|
||||
(COALESCE(sp.sets_with_price, 0) + COALESCE(ipp.individual_parts_with_price, 0) +
|
||||
COALESCE(imp.individual_minifigs_with_price, 0) + COALESCE(plp.lots_with_price, 0)), 2)
|
||||
ELSE 0
|
||||
END AS "avg_price_per_item",
|
||||
|
||||
(SELECT MIN(price) FROM (
|
||||
SELECT "purchase_price" AS price FROM "bricktracker_sets"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_parts"
|
||||
WHERE "purchase_price" IS NOT NULL AND "lot_id" IS NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_minifigures"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_part_lots"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
)) AS "min_price",
|
||||
|
||||
(SELECT MAX(price) FROM (
|
||||
SELECT "purchase_price" AS price FROM "bricktracker_sets"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_parts"
|
||||
WHERE "purchase_price" IS NOT NULL AND "lot_id" IS NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_minifigures"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
UNION ALL
|
||||
SELECT "purchase_price" FROM "bricktracker_individual_part_lots"
|
||||
WHERE "purchase_price" IS NOT NULL
|
||||
AND strftime('%Y', datetime("purchase_date", 'unixepoch')) = ay.purchase_year
|
||||
)) AS "max_price",
|
||||
|
||||
-- Set-specific statistics (for backward compatibility, may be NULL if no sets purchased this year)
|
||||
sp.oldest_set_year,
|
||||
sp.newest_set_year,
|
||||
sp.avg_set_release_year,
|
||||
|
||||
-- Backward compatibility: avg_price_per_set uses combined average (duplicate calculation)
|
||||
CASE
|
||||
WHEN (COALESCE(sp.sets_with_price, 0) + COALESCE(ipp.individual_parts_with_price, 0) +
|
||||
COALESCE(imp.individual_minifigs_with_price, 0) + COALESCE(plp.lots_with_price, 0)) > 0
|
||||
THEN ROUND((COALESCE(sp.sets_total_spent, 0) + COALESCE(ipp.individual_parts_total_spent, 0) +
|
||||
COALESCE(imp.individual_minifigs_total_spent, 0) + COALESCE(plp.lots_total_spent, 0)) /
|
||||
(COALESCE(sp.sets_with_price, 0) + COALESCE(ipp.individual_parts_with_price, 0) +
|
||||
COALESCE(imp.individual_minifigs_with_price, 0) + COALESCE(plp.lots_with_price, 0)), 2)
|
||||
ELSE 0
|
||||
END AS "avg_price_per_set",
|
||||
|
||||
-- Problem statistics
|
||||
COALESCE(sp.set_missing_parts, 0) + COALESCE(ipp.individual_missing_parts, 0) AS "missing_parts",
|
||||
COALESCE(sp.set_damaged_parts, 0) + COALESCE(ipp.individual_damaged_parts, 0) AS "damaged_parts",
|
||||
|
||||
-- Diversity statistics
|
||||
COALESCE(sp.unique_themes, 0) AS "unique_themes",
|
||||
(SELECT COUNT(DISTINCT location) FROM (
|
||||
SELECT COALESCE(sp.set_unique_purchase_locations, 0) AS location
|
||||
UNION
|
||||
SELECT COALESCE(ipp.individual_part_unique_purchase_locations, 0)
|
||||
UNION
|
||||
SELECT COALESCE(imp.individual_minifig_unique_purchase_locations, 0)
|
||||
UNION
|
||||
SELECT COALESCE(plp.lot_unique_purchase_locations, 0)
|
||||
)) AS "unique_purchase_locations",
|
||||
|
||||
COALESCE(sp.months_with_purchases, 0) AS "months_with_purchases"
|
||||
|
||||
FROM all_years ay
|
||||
LEFT JOIN set_purchases sp ON ay.purchase_year = sp.purchase_year
|
||||
LEFT JOIN individual_part_purchases ipp ON ay.purchase_year = ipp.purchase_year
|
||||
LEFT JOIN individual_minifig_purchases imp ON ay.purchase_year = imp.purchase_year
|
||||
LEFT JOIN part_lot_purchases plp ON ay.purchase_year = plp.purchase_year
|
||||
|
||||
ORDER BY ay.purchase_year DESC
|
||||
@@ -1,40 +1,130 @@
|
||||
-- Storage Location Statistics
|
||||
-- Shows statistics grouped by storage location
|
||||
-- Includes sets, individual parts, individual minifigures, and part lots
|
||||
|
||||
WITH
|
||||
|
||||
-- Set statistics by storage
|
||||
set_storage_stats AS (
|
||||
SELECT
|
||||
"bricktracker_sets"."storage" AS "storage_id",
|
||||
COUNT("bricktracker_sets"."id") AS "set_count",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_set_count",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "total_value",
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "damaged_parts",
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "total_minifigures"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."storage" IS NOT NULL
|
||||
GROUP BY "bricktracker_sets"."storage"
|
||||
),
|
||||
|
||||
-- Individual part statistics by storage
|
||||
individual_part_storage_stats AS (
|
||||
SELECT
|
||||
"storage" AS "storage_id",
|
||||
COUNT(*) AS "individual_part_count",
|
||||
SUM("quantity") AS "individual_part_quantity",
|
||||
SUM("missing") AS "individual_missing_parts",
|
||||
SUM("damaged") AS "individual_damaged_parts",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "individual_parts_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "individual_total_value"
|
||||
FROM "bricktracker_individual_parts"
|
||||
WHERE "storage" IS NOT NULL AND "lot_id" IS NULL
|
||||
GROUP BY "storage"
|
||||
),
|
||||
|
||||
-- Individual minifigure statistics by storage
|
||||
individual_minifig_storage_stats AS (
|
||||
SELECT
|
||||
"storage" AS "storage_id",
|
||||
COUNT(*) AS "individual_minifig_count",
|
||||
SUM("quantity") AS "individual_minifig_quantity",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "individual_minifigs_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "individual_minifig_total_value"
|
||||
FROM "bricktracker_individual_minifigures"
|
||||
WHERE "storage" IS NOT NULL
|
||||
GROUP BY "storage"
|
||||
),
|
||||
|
||||
-- Part lot statistics by storage
|
||||
part_lot_storage_stats AS (
|
||||
SELECT
|
||||
"storage" AS "storage_id",
|
||||
COUNT(*) AS "lot_count",
|
||||
COUNT(CASE WHEN "purchase_price" IS NOT NULL THEN 1 END) AS "lots_with_price",
|
||||
ROUND(SUM("purchase_price"), 2) AS "lot_total_value"
|
||||
FROM "bricktracker_individual_part_lots"
|
||||
WHERE "storage" IS NOT NULL
|
||||
GROUP BY "storage"
|
||||
)
|
||||
|
||||
-- Combine all statistics
|
||||
SELECT
|
||||
"bricktracker_sets"."storage" AS "storage_id",
|
||||
COALESCE(sss.storage_id, ipss.storage_id, imss.storage_id, plss.storage_id) AS "storage_id",
|
||||
"bricktracker_metadata_storages"."name" AS "storage_name",
|
||||
COUNT("bricktracker_sets"."id") AS "set_count",
|
||||
COUNT(DISTINCT "bricktracker_sets"."set") AS "unique_set_count",
|
||||
SUM("rebrickable_sets"."number_of_parts") AS "total_parts",
|
||||
ROUND(AVG("rebrickable_sets"."number_of_parts"), 0) AS "avg_parts_per_set",
|
||||
-- Financial statistics per storage
|
||||
COUNT(CASE WHEN "bricktracker_sets"."purchase_price" IS NOT NULL THEN 1 END) AS "sets_with_price",
|
||||
ROUND(SUM("bricktracker_sets"."purchase_price"), 2) AS "total_value",
|
||||
ROUND(AVG("bricktracker_sets"."purchase_price"), 2) AS "avg_price",
|
||||
-- Problem statistics per storage
|
||||
COALESCE(SUM("problem_stats"."missing_parts"), 0) AS "missing_parts",
|
||||
COALESCE(SUM("problem_stats"."damaged_parts"), 0) AS "damaged_parts",
|
||||
-- Minifigure statistics per storage
|
||||
COALESCE(SUM("minifigure_stats"."minifigure_count"), 0) AS "total_minifigures"
|
||||
FROM "bricktracker_sets"
|
||||
INNER JOIN "rebrickable_sets" ON "bricktracker_sets"."set" = "rebrickable_sets"."set"
|
||||
LEFT JOIN "bricktracker_metadata_storages" ON "bricktracker_sets"."storage" = "bricktracker_metadata_storages"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_parts"."id",
|
||||
SUM("bricktracker_parts"."missing") AS "missing_parts",
|
||||
SUM("bricktracker_parts"."damaged") AS "damaged_parts"
|
||||
FROM "bricktracker_parts"
|
||||
GROUP BY "bricktracker_parts"."id"
|
||||
) "problem_stats" ON "bricktracker_sets"."id" = "problem_stats"."id"
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"bricktracker_minifigures"."id",
|
||||
SUM("bricktracker_minifigures"."quantity") AS "minifigure_count"
|
||||
FROM "bricktracker_minifigures"
|
||||
GROUP BY "bricktracker_minifigures"."id"
|
||||
) "minifigure_stats" ON "bricktracker_sets"."id" = "minifigure_stats"."id"
|
||||
WHERE "bricktracker_sets"."storage" IS NOT NULL
|
||||
GROUP BY "bricktracker_sets"."storage", "bricktracker_metadata_storages"."name"
|
||||
ORDER BY "set_count" DESC, "storage_name" ASC
|
||||
|
||||
-- Set counts
|
||||
COALESCE(sss.set_count, 0) AS "set_count",
|
||||
COALESCE(sss.unique_set_count, 0) AS "unique_set_count",
|
||||
|
||||
-- Individual item counts
|
||||
COALESCE(ipss.individual_part_count, 0) AS "individual_part_count",
|
||||
COALESCE(imss.individual_minifig_count, 0) AS "individual_minifig_count",
|
||||
COALESCE(plss.lot_count, 0) AS "lot_count",
|
||||
|
||||
-- Part counts
|
||||
COALESCE(sss.total_parts, 0) + COALESCE(ipss.individual_part_quantity, 0) AS "total_parts",
|
||||
CASE
|
||||
WHEN COALESCE(sss.set_count, 0) > 0
|
||||
THEN ROUND(CAST(COALESCE(sss.total_parts, 0) AS FLOAT) / sss.set_count, 0)
|
||||
ELSE 0
|
||||
END AS "avg_parts_per_set",
|
||||
|
||||
-- Financial statistics
|
||||
COALESCE(sss.sets_with_price, 0) + COALESCE(ipss.individual_parts_with_price, 0) +
|
||||
COALESCE(imss.individual_minifigs_with_price, 0) + COALESCE(plss.lots_with_price, 0) AS "items_with_price",
|
||||
ROUND(COALESCE(sss.total_value, 0) + COALESCE(ipss.individual_total_value, 0) +
|
||||
COALESCE(imss.individual_minifig_total_value, 0) + COALESCE(plss.lot_total_value, 0), 2) AS "total_value",
|
||||
CASE
|
||||
WHEN (COALESCE(sss.sets_with_price, 0) + COALESCE(ipss.individual_parts_with_price, 0) +
|
||||
COALESCE(imss.individual_minifigs_with_price, 0) + COALESCE(plss.lots_with_price, 0)) > 0
|
||||
THEN ROUND((COALESCE(sss.total_value, 0) + COALESCE(ipss.individual_total_value, 0) +
|
||||
COALESCE(imss.individual_minifig_total_value, 0) + COALESCE(plss.lot_total_value, 0)) /
|
||||
(COALESCE(sss.sets_with_price, 0) + COALESCE(ipss.individual_parts_with_price, 0) +
|
||||
COALESCE(imss.individual_minifigs_with_price, 0) + COALESCE(plss.lots_with_price, 0)), 2)
|
||||
ELSE 0
|
||||
END AS "avg_price",
|
||||
|
||||
-- Problem statistics
|
||||
COALESCE(sss.missing_parts, 0) + COALESCE(ipss.individual_missing_parts, 0) AS "missing_parts",
|
||||
COALESCE(sss.damaged_parts, 0) + COALESCE(ipss.individual_damaged_parts, 0) AS "damaged_parts",
|
||||
|
||||
-- Minifigure counts
|
||||
COALESCE(sss.total_minifigures, 0) + COALESCE(imss.individual_minifig_quantity, 0) AS "total_minifigures"
|
||||
|
||||
FROM set_storage_stats sss
|
||||
FULL OUTER JOIN individual_part_storage_stats ipss ON sss.storage_id = ipss.storage_id
|
||||
FULL OUTER JOIN individual_minifig_storage_stats imss ON COALESCE(sss.storage_id, ipss.storage_id) = imss.storage_id
|
||||
FULL OUTER JOIN part_lot_storage_stats plss ON COALESCE(sss.storage_id, ipss.storage_id, imss.storage_id) = plss.storage_id
|
||||
LEFT JOIN "bricktracker_metadata_storages" ON COALESCE(sss.storage_id, ipss.storage_id, imss.storage_id, plss.storage_id) = "bricktracker_metadata_storages"."id"
|
||||
|
||||
ORDER BY "set_count" DESC, "storage_name" ASC
|
||||
|
||||
Reference in New Issue
Block a user