Image Tagging System

Implement a flexible tagging system for images using a junction table for many-to-many relationships

All recipes· image-management· 12 minutesbeginner

Image Tagging System

Objective

Implement a flexible tagging system for images using a many-to-many relationship. This allows each image to have multiple tags and each tag to be applied to multiple images.

Step 1: Create Images Table

Create the main images table.

CREATE TABLE images (
    image_id INTEGER PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    filename VARCHAR(255) NOT NULL,
    image IMAGE(JPEG),
    description TEXT,
    uploaded_by VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Step 2: Create Tags Table

Create a table for storing unique tags.

CREATE TABLE tags (
    tag_id INTEGER PRIMARY KEY,
    tag_name VARCHAR(50) NOT NULL UNIQUE,
    tag_category VARCHAR(50),
    usage_count INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Step 3: Create Junction Table

Create the many-to-many relationship table.

CREATE TABLE image_tags (
    image_id INTEGER NOT NULL,
    tag_id INTEGER NOT NULL,
    tagged_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    tagged_by VARCHAR(100),
    PRIMARY KEY (image_id, tag_id),
    FOREIGN KEY (image_id) REFERENCES images(image_id),
    FOREIGN KEY (tag_id) REFERENCES tags(tag_id)
);

Step 4: Insert Sample Images

Add sample images to the system.

INSERT INTO images (image_id, title, filename, description, uploaded_by) VALUES
    (1, 'Mountain Sunrise', 'mountain_sunrise.jpg', 'Beautiful mountain at dawn', 'photographer1'),
    (2, 'City Night', 'city_night.jpg', 'Urban skyline after dark', 'photographer2'),
    (3, 'Beach Waves', 'beach_waves.jpg', 'Ocean waves crashing', 'photographer1'),
    (4, 'Forest Trail', 'forest_trail.jpg', 'Hiking path through woods', 'photographer3'),
    (5, 'Portrait Studio', 'portrait_studio.jpg', 'Professional headshot', 'photographer2');

Step 5: Insert Tags

Create a set of reusable tags.

INSERT INTO tags (tag_id, tag_name, tag_category) VALUES
    (1, 'landscape', 'subject'),
    (2, 'nature', 'subject'),
    (3, 'urban', 'subject'),
    (4, 'portrait', 'subject'),
    (5, 'sunrise', 'time'),
    (6, 'sunset', 'time'),
    (7, 'night', 'time'),
    (8, 'outdoor', 'location'),
    (9, 'indoor', 'location'),
    (10, 'water', 'element'),
    (11, 'mountains', 'element'),
    (12, 'trees', 'element');

Step 6: Tag the Images

Associate tags with images through the junction table.

INSERT INTO image_tags (image_id, tag_id, tagged_by) VALUES
    -- Mountain Sunrise tags
    (1, 1, 'photographer1'),   -- landscape
    (1, 2, 'photographer1'),   -- nature
    (1, 5, 'photographer1'),   -- sunrise
    (1, 8, 'photographer1'),   -- outdoor
    (1, 11, 'photographer1'),  -- mountains

    -- City Night tags
    (2, 3, 'photographer2'),   -- urban
    (2, 7, 'photographer2'),   -- night
    (2, 8, 'photographer2'),   -- outdoor

    -- Beach Waves tags
    (3, 1, 'photographer1'),   -- landscape
    (3, 2, 'photographer1'),   -- nature
    (3, 8, 'photographer1'),   -- outdoor
    (3, 10, 'photographer1'),  -- water

    -- Forest Trail tags
    (4, 1, 'photographer3'),   -- landscape
    (4, 2, 'photographer3'),   -- nature
    (4, 8, 'photographer3'),   -- outdoor
    (4, 12, 'photographer3'),  -- trees

    -- Portrait Studio tags
    (5, 4, 'photographer2'),   -- portrait
    (5, 9, 'photographer2');   -- indoor

Step 7: Update Tag Usage Counts

Keep track of how often each tag is used.

UPDATE tags
SET usage_count = (
    SELECT COUNT(*) FROM image_tags WHERE image_tags.tag_id = tags.tag_id
);

SELECT tag_name, tag_category, usage_count
FROM tags
ORDER BY usage_count DESC;

Step 8: Find Images by Tag

Query images with a specific tag.

SELECT
    i.title,
    i.filename,
    i.uploaded_by
FROM images i
INNER JOIN image_tags it ON i.image_id = it.image_id
INNER JOIN tags t ON it.tag_id = t.tag_id
WHERE t.tag_name = 'landscape';

Step 9: Get All Tags for an Image

List all tags associated with a specific image.

SELECT
    i.title,
    t.tag_name,
    t.tag_category
FROM images i
INNER JOIN image_tags it ON i.image_id = it.image_id
INNER JOIN tags t ON it.tag_id = t.tag_id
WHERE i.image_id = 1
ORDER BY t.tag_category, t.tag_name;

Step 10: Find Images with Multiple Tags

Search for images matching multiple tags (AND logic).

SELECT
    i.title,
    COUNT(DISTINCT t.tag_id) as matching_tags
FROM images i
INNER JOIN image_tags it ON i.image_id = it.image_id
INNER JOIN tags t ON it.tag_id = t.tag_id
WHERE t.tag_name IN ('landscape', 'nature', 'outdoor')
GROUP BY i.image_id, i.title
HAVING COUNT(DISTINCT t.tag_id) = 3;

Step 11: Tag Cloud Query

Generate data for a tag cloud visualization.

SELECT
    tag_name,
    tag_category,
    usage_count,
    CASE
        WHEN usage_count >= 4 THEN 'large'
        WHEN usage_count >= 2 THEN 'medium'
        ELSE 'small'
    END as cloud_size
FROM tags
WHERE usage_count > 0
ORDER BY usage_count DESC;

Step 12: Images by Tag Category

Group images by tag category.

SELECT
    t.tag_category,
    COUNT(DISTINCT i.image_id) as image_count,
    COUNT(it.image_id) as tag_applications
FROM tags t
INNER JOIN image_tags it ON t.tag_id = it.tag_id
INNER JOIN images i ON it.image_id = i.image_id
GROUP BY t.tag_category
ORDER BY image_count DESC;

Cleanup (Optional)

DROP TABLE IF EXISTS image_tags;
DROP TABLE IF EXISTS tags;
DROP TABLE IF EXISTS images;

Expected Outcomes

  • Many-to-many relationship established
  • Images can have multiple tags
  • Tags reusable across images
  • Tag usage statistics tracked
  • Complex tag queries supported

Key Concepts Learned

  • Junction table pattern
  • Many-to-many relationships
  • Composite primary keys
  • Multi-table JOINs
  • Tag counting and statistics

Tags

sqlbeginnerimagestagsmany-to-manyjunction-table

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE