## Cross-join option
**watchlist_label table**
| column | type | description
| ----- | ----- | -----
| wll_id | int | unique id for row
| wll_user | int | user_id for label creator
| wll_name | varchar 255 | label text
**watchlist_label_member table**
| column | type | description
| ----- | ----- | -----
| wlm_label | int | Link to wll_id
| wlm_item | int | Link to wl_id
## Copy option
With denormalized namespace/title
```lang=sql
CREATE TABLE `page_tag` (
-- Link to page_tag_def.ptd_id
pt_tag INT UNSIGNED NOT NULL,
-- Link to page_id
pt_page INT DEFAULT 0 NOT NULL,
-- Denormalized page_namespace
pt_namespace INT DEFAULT 0 NOT NULL,
-- Denormalized page_title
pt_title VARBINARY(255) DEFAULT '' NOT NULL,
-- For ChangesListSpecialPage filtering etc.
PRIMARY KEY (pt_namespace, pt_title, pt_tag_id),
-- For Special:EditWatchlist sorting
UNIQUE INDEX (pt_tag_id, pt_namespace, pt_title)
);
CREATE TABLE `page_tag_def` (
ptd_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
-- A static enum, with 0 for private watchlist, 1 for shared list
ptd_type TINYINT UNSIGNED DEFAULT 0 NOT NULL,
-- A link to user_id, or zero for a public/shared list
ptd_owner INT UNSIGNED DEFAULT 0 NOT NULL,
-- The list/label name, or an empty string for the main watchlist union
ptd_name VARBINARY(255) DEFAULT '' NOT NULL,
PRIMARY KEY (ptd_id),
UNIQUE KEY (ptd_type, ptd_owner, ptd_name)
);
```
### Sample queries
Watchlist default filter
```lang=sql
SET @pt_id = (SELECT ptd_id FROM page_tag_def WHERE ptd_type=0 AND ptd_owner=@user AND ptd_name='');
SELECT ...
FROM recentchanges
JOIN page_tag ON rc_namespace=pt_namespace AND rc_title=pt_title
WHERE pt_id=@pt_id;
```
After fixing the rc_cur_id index to include rc_timestamp so that it can efficiently handle timestamp ranges:
```lang=sql
SELECT ... FROM recentchanges JOIN page_tag ON rc_cur_id=pt_page WHERE pt_id=@id;
```
Display subquery:
```lang=sql
SELECT GROUP_CONCAT(ptd_name)
FROM page_tag
JOIN page_tag_def ON ptd_id=pt_tag AND ptd_type=0 AND ptd_owner=@user
WHERE pt_page=rc_cur_id
```
Filter by several watchlist labels, analogous to change_tag filter:
```lang=sql
SELECT DISTINCT ...
FROM recentchanges
JOIN page_tag ON rc_cur_id=pt_page WHERE pt_id IN (...)
GROUP BY rc_timestamp, rc_id;
```