test: migrate join tests from duckdb, part3 (#6881)

* test: migrate join tests

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: update test results after rebasing main branch

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: unstable query sort results and natural_join test

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: count(*) with joining

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix: unstable query sort results and style

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
This commit is contained in:
dennis zhuang
2025-09-12 12:20:00 +08:00
committed by Weny Xu
parent 849ae8ebb6
commit ed17997449
72 changed files with 5262 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
-- Migrated from DuckDB test: test/sql/join/cross_product/ advanced tests
-- Tests advanced cross join scenarios
CREATE TABLE products(prod_id INTEGER, prod_name VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE stores(store_id INTEGER, store_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE categories(cat_id INTEGER, cat_name VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO products VALUES
(1, 'Laptop', 999.99, 1000), (2, 'Mouse', 29.99, 2000), (3, 'Monitor', 299.99, 3000);
Affected Rows: 3
INSERT INTO stores VALUES
(1, 'TechStore', 'NYC', 1000), (2, 'GadgetShop', 'LA', 2000);
Affected Rows: 2
INSERT INTO categories VALUES
(1, 'Electronics', 1000), (2, 'Accessories', 2000);
Affected Rows: 2
-- Basic cross join
SELECT
p.prod_name, s.store_name, s.city
FROM products p
CROSS JOIN stores s
ORDER BY p.prod_id, s.store_id;
+-----------+------------+------+
| prod_name | store_name | city |
+-----------+------------+------+
| Laptop | TechStore | NYC |
| Laptop | GadgetShop | LA |
| Mouse | TechStore | NYC |
| Mouse | GadgetShop | LA |
| Monitor | TechStore | NYC |
| Monitor | GadgetShop | LA |
+-----------+------------+------+
-- Cross join with filtering
SELECT
p.prod_name, s.store_name, p.price
FROM products p
CROSS JOIN stores s
WHERE p.price > 100.00
ORDER BY p.price DESC, s.store_name;
+-----------+------------+--------+
| prod_name | store_name | price |
+-----------+------------+--------+
| Laptop | GadgetShop | 999.99 |
| Laptop | TechStore | 999.99 |
| Monitor | GadgetShop | 299.99 |
| Monitor | TechStore | 299.99 |
+-----------+------------+--------+
-- Triple cross join
SELECT
p.prod_name, s.store_name, c.cat_name,
CASE WHEN p.price > 500 THEN 'Premium' ELSE 'Standard' END as tier
FROM products p
CROSS JOIN stores s
CROSS JOIN categories c
ORDER BY p.prod_id, s.store_id, c.cat_id;
+-----------+------------+-------------+----------+
| prod_name | store_name | cat_name | tier |
+-----------+------------+-------------+----------+
| Laptop | TechStore | Electronics | Premium |
| Laptop | TechStore | Accessories | Premium |
| Laptop | GadgetShop | Electronics | Premium |
| Laptop | GadgetShop | Accessories | Premium |
| Mouse | TechStore | Electronics | Standard |
| Mouse | TechStore | Accessories | Standard |
| Mouse | GadgetShop | Electronics | Standard |
| Mouse | GadgetShop | Accessories | Standard |
| Monitor | TechStore | Electronics | Standard |
| Monitor | TechStore | Accessories | Standard |
| Monitor | GadgetShop | Electronics | Standard |
| Monitor | GadgetShop | Accessories | Standard |
+-----------+------------+-------------+----------+
-- Cross join with aggregation
SELECT
s.city,
COUNT(*) as product_store_combinations,
AVG(p.price) as avg_price,
SUM(p.price) as total_inventory_value
FROM products p
CROSS JOIN stores s
GROUP BY s.city
ORDER BY s.city;
+------+----------------------------+-------------------+-----------------------+
| city | product_store_combinations | avg_price | total_inventory_value |
+------+----------------------------+-------------------+-----------------------+
| LA | 3 | 443.3233333333333 | 1329.97 |
| NYC | 3 | 443.3233333333333 | 1329.97 |
+------+----------------------------+-------------------+-----------------------+
-- Cross join for inventory matrix
SELECT
p.prod_name,
SUM(CASE WHEN s.city = 'NYC' THEN 1 ELSE 0 END) as nyc_availability,
SUM(CASE WHEN s.city = 'LA' THEN 1 ELSE 0 END) as la_availability,
COUNT(s.store_id) as total_store_availability
FROM products p
CROSS JOIN stores s
GROUP BY p.prod_name, p.prod_id
ORDER BY p.prod_id;
+-----------+------------------+-----------------+--------------------------+
| prod_name | nyc_availability | la_availability | total_store_availability |
+-----------+------------------+-----------------+--------------------------+
| Laptop | 1 | 1 | 2 |
| Mouse | 1 | 1 | 2 |
| Monitor | 1 | 1 | 2 |
+-----------+------------------+-----------------+--------------------------+
-- Cross join with conditions and calculations
SELECT
p.prod_name,
s.store_name,
p.price,
p.price * 0.1 as store_commission,
p.price * 1.08 as price_with_tax
FROM products p
CROSS JOIN stores s
WHERE p.price BETWEEN 25.00 AND 1000.00
ORDER BY p.price DESC, s.store_name;
+-----------+------------+--------+--------------------+--------------------+
| prod_name | store_name | price | store_commission | price_with_tax |
+-----------+------------+--------+--------------------+--------------------+
| Laptop | GadgetShop | 999.99 | 99.99900000000001 | 1079.9892 |
| Laptop | TechStore | 999.99 | 99.99900000000001 | 1079.9892 |
| Monitor | GadgetShop | 299.99 | 29.999000000000002 | 323.98920000000004 |
| Monitor | TechStore | 299.99 | 29.999000000000002 | 323.98920000000004 |
| Mouse | GadgetShop | 29.99 | 2.999 | 32.3892 |
| Mouse | TechStore | 29.99 | 2.999 | 32.3892 |
+-----------+------------+--------+--------------------+--------------------+
DROP TABLE products;
Affected Rows: 0
DROP TABLE stores;
Affected Rows: 0
DROP TABLE categories;
Affected Rows: 0

View File

@@ -0,0 +1,81 @@
-- Migrated from DuckDB test: test/sql/join/cross_product/ advanced tests
-- Tests advanced cross join scenarios
CREATE TABLE products(prod_id INTEGER, prod_name VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE stores(store_id INTEGER, store_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE categories(cat_id INTEGER, cat_name VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO products VALUES
(1, 'Laptop', 999.99, 1000), (2, 'Mouse', 29.99, 2000), (3, 'Monitor', 299.99, 3000);
INSERT INTO stores VALUES
(1, 'TechStore', 'NYC', 1000), (2, 'GadgetShop', 'LA', 2000);
INSERT INTO categories VALUES
(1, 'Electronics', 1000), (2, 'Accessories', 2000);
-- Basic cross join
SELECT
p.prod_name, s.store_name, s.city
FROM products p
CROSS JOIN stores s
ORDER BY p.prod_id, s.store_id;
-- Cross join with filtering
SELECT
p.prod_name, s.store_name, p.price
FROM products p
CROSS JOIN stores s
WHERE p.price > 100.00
ORDER BY p.price DESC, s.store_name;
-- Triple cross join
SELECT
p.prod_name, s.store_name, c.cat_name,
CASE WHEN p.price > 500 THEN 'Premium' ELSE 'Standard' END as tier
FROM products p
CROSS JOIN stores s
CROSS JOIN categories c
ORDER BY p.prod_id, s.store_id, c.cat_id;
-- Cross join with aggregation
SELECT
s.city,
COUNT(*) as product_store_combinations,
AVG(p.price) as avg_price,
SUM(p.price) as total_inventory_value
FROM products p
CROSS JOIN stores s
GROUP BY s.city
ORDER BY s.city;
-- Cross join for inventory matrix
SELECT
p.prod_name,
SUM(CASE WHEN s.city = 'NYC' THEN 1 ELSE 0 END) as nyc_availability,
SUM(CASE WHEN s.city = 'LA' THEN 1 ELSE 0 END) as la_availability,
COUNT(s.store_id) as total_store_availability
FROM products p
CROSS JOIN stores s
GROUP BY p.prod_name, p.prod_id
ORDER BY p.prod_id;
-- Cross join with conditions and calculations
SELECT
p.prod_name,
s.store_name,
p.price,
p.price * 0.1 as store_commission,
p.price * 1.08 as price_with_tax
FROM products p
CROSS JOIN stores s
WHERE p.price BETWEEN 25.00 AND 1000.00
ORDER BY p.price DESC, s.store_name;
DROP TABLE products;
DROP TABLE stores;
DROP TABLE categories;

View File

@@ -0,0 +1,63 @@
-- Migrated from DuckDB test: test/sql/join/cross_product/test_cross_product.test
-- Tests CROSS JOIN functionality
CREATE TABLE small_table (a INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE another_table (b INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO small_table VALUES (1, 1000), (2, 2000);
Affected Rows: 2
INSERT INTO another_table VALUES (10, 3000), (20, 4000), (30, 5000);
Affected Rows: 3
-- Basic CROSS JOIN
SELECT * FROM small_table CROSS JOIN another_table ORDER BY a, b;
+---+---------------------+----+---------------------+
| a | ts | b | ts |
+---+---------------------+----+---------------------+
| 1 | 1970-01-01T00:00:01 | 10 | 1970-01-01T00:00:03 |
| 1 | 1970-01-01T00:00:01 | 20 | 1970-01-01T00:00:04 |
| 1 | 1970-01-01T00:00:01 | 30 | 1970-01-01T00:00:05 |
| 2 | 1970-01-01T00:00:02 | 10 | 1970-01-01T00:00:03 |
| 2 | 1970-01-01T00:00:02 | 20 | 1970-01-01T00:00:04 |
| 2 | 1970-01-01T00:00:02 | 30 | 1970-01-01T00:00:05 |
+---+---------------------+----+---------------------+
-- CROSS JOIN with WHERE filter
SELECT * FROM small_table CROSS JOIN another_table WHERE a + b < 25 ORDER BY a, b;
+---+---------------------+----+---------------------+
| a | ts | b | ts |
+---+---------------------+----+---------------------+
| 1 | 1970-01-01T00:00:01 | 10 | 1970-01-01T00:00:03 |
| 1 | 1970-01-01T00:00:01 | 20 | 1970-01-01T00:00:04 |
| 2 | 1970-01-01T00:00:02 | 10 | 1970-01-01T00:00:03 |
| 2 | 1970-01-01T00:00:02 | 20 | 1970-01-01T00:00:04 |
+---+---------------------+----+---------------------+
-- CROSS JOIN with aliases
SELECT s.a, t.b FROM small_table s CROSS JOIN another_table t WHERE s.a = 1 ORDER BY b;
+---+----+
| a | b |
+---+----+
| 1 | 10 |
| 1 | 20 |
| 1 | 30 |
+---+----+
DROP TABLE another_table;
Affected Rows: 0
DROP TABLE small_table;
Affected Rows: 0

View File

@@ -0,0 +1,23 @@
-- Migrated from DuckDB test: test/sql/join/cross_product/test_cross_product.test
-- Tests CROSS JOIN functionality
CREATE TABLE small_table (a INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE another_table (b INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO small_table VALUES (1, 1000), (2, 2000);
INSERT INTO another_table VALUES (10, 3000), (20, 4000), (30, 5000);
-- Basic CROSS JOIN
SELECT * FROM small_table CROSS JOIN another_table ORDER BY a, b;
-- CROSS JOIN with WHERE filter
SELECT * FROM small_table CROSS JOIN another_table WHERE a + b < 25 ORDER BY a, b;
-- CROSS JOIN with aliases
SELECT s.a, t.b FROM small_table s CROSS JOIN another_table t WHERE s.a = 1 ORDER BY b;
DROP TABLE another_table;
DROP TABLE small_table;

View File

@@ -0,0 +1,61 @@
-- Migrated from DuckDB test: test/sql/join/full_outer/test_full_outer_join.test
-- Tests FULL OUTER JOIN scenarios
CREATE TABLE left_full("id" INTEGER, "name" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE right_full("id" INTEGER, "value" INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO left_full VALUES (1, 'Alice', 1000), (2, 'Bob', 2000), (3, 'Carol', 3000);
Affected Rows: 3
INSERT INTO right_full VALUES (2, 200, 4000), (3, 300, 5000), (4, 400, 6000);
Affected Rows: 3
-- Basic FULL OUTER JOIN
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
+----+-------+---------------------+----+-------+---------------------+
| id | name | ts | id | value | ts |
+----+-------+---------------------+----+-------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | | | |
| 2 | Bob | 1970-01-01T00:00:02 | 2 | 200 | 1970-01-01T00:00:04 |
| 3 | Carol | 1970-01-01T00:00:03 | 3 | 300 | 1970-01-01T00:00:05 |
| | | | 4 | 400 | 1970-01-01T00:00:06 |
+----+-------+---------------------+----+-------+---------------------+
-- FULL OUTER JOIN with WHERE on result
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" WHERE l."name" IS NULL OR r."value" IS NULL ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
+----+-------+---------------------+----+-------+---------------------+
| id | name | ts | id | value | ts |
+----+-------+---------------------+----+-------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | | | |
| | | | 4 | 400 | 1970-01-01T00:00:06 |
+----+-------+---------------------+----+-------+---------------------+
-- FULL OUTER JOIN with complex conditions
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" AND r."value" > 250 ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
+----+-------+---------------------+----+-------+---------------------+
| id | name | ts | id | value | ts |
+----+-------+---------------------+----+-------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | | | |
| 2 | Bob | 1970-01-01T00:00:02 | | | |
| 3 | Carol | 1970-01-01T00:00:03 | 3 | 300 | 1970-01-01T00:00:05 |
| | | | 2 | 200 | 1970-01-01T00:00:04 |
| | | | 4 | 400 | 1970-01-01T00:00:06 |
+----+-------+---------------------+----+-------+---------------------+
DROP TABLE right_full;
Affected Rows: 0
DROP TABLE left_full;
Affected Rows: 0

View File

@@ -0,0 +1,23 @@
-- Migrated from DuckDB test: test/sql/join/full_outer/test_full_outer_join.test
-- Tests FULL OUTER JOIN scenarios
CREATE TABLE left_full("id" INTEGER, "name" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE right_full("id" INTEGER, "value" INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO left_full VALUES (1, 'Alice', 1000), (2, 'Bob', 2000), (3, 'Carol', 3000);
INSERT INTO right_full VALUES (2, 200, 4000), (3, 300, 5000), (4, 400, 6000);
-- Basic FULL OUTER JOIN
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
-- FULL OUTER JOIN with WHERE on result
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" WHERE l."name" IS NULL OR r."value" IS NULL ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
-- FULL OUTER JOIN with complex conditions
SELECT * FROM left_full l FULL OUTER JOIN right_full r ON l."id" = r."id" AND r."value" > 250 ORDER BY l."id" NULLS LAST, r."id" NULLS LAST;
DROP TABLE right_full;
DROP TABLE left_full;

View File

@@ -0,0 +1,140 @@
-- Migrated from DuckDB test: test/sql/join/ hash join tests
-- Tests complex hash join scenarios
CREATE TABLE large_table_a("id" INTEGER, value_a VARCHAR, num_a INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE large_table_b("id" INTEGER, value_b VARCHAR, num_b INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO large_table_a VALUES
(1, 'alpha', 100, 1000), (2, 'beta', 200, 2000), (3, 'gamma', 300, 3000),
(4, 'delta', 400, 4000), (5, 'epsilon', 500, 5000), (6, 'zeta', 600, 6000),
(7, 'eta', 700, 7000), (8, 'theta', 800, 8000), (9, 'iota', 900, 9000),
(10, 'kappa', 1000, 10000);
Affected Rows: 10
INSERT INTO large_table_b VALUES
(2, 'second', 20, 1000), (4, 'fourth', 40, 2000), (6, 'sixth', 60, 3000),
(8, 'eighth', 80, 4000), (10, 'tenth', 100, 5000), (12, 'twelfth', 120, 6000),
(14, 'fourteenth', 140, 7000), (16, 'sixteenth', 160, 8000);
Affected Rows: 8
-- Hash join with exact match
SELECT
a."id", a.value_a, a.num_a, b.value_b, b.num_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
ORDER BY a."id";
+----+---------+-------+---------+-------+
| id | value_a | num_a | value_b | num_b |
+----+---------+-------+---------+-------+
| 2 | beta | 200 | second | 20 |
| 4 | delta | 400 | fourth | 40 |
| 6 | zeta | 600 | sixth | 60 |
| 8 | theta | 800 | eighth | 80 |
| 10 | kappa | 1000 | tenth | 100 |
+----+---------+-------+---------+-------+
-- Hash join with multiple key conditions
SELECT
a."id", a.value_a, b.value_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id" AND a.num_a > b.num_b * 5
ORDER BY a."id";
+----+---------+---------+
| id | value_a | value_b |
+----+---------+---------+
| 2 | beta | second |
| 4 | delta | fourth |
| 6 | zeta | sixth |
| 8 | theta | eighth |
| 10 | kappa | tenth |
+----+---------+---------+
-- Hash join with aggregation on both sides
SELECT
joined_data."id",
joined_data.combined_num,
joined_data.value_concat
FROM (
SELECT
a."id",
a.num_a + b.num_b as combined_num,
a.value_a || '-' || b.value_b as value_concat
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
) joined_data
WHERE joined_data.combined_num > 500
ORDER BY joined_data.combined_num DESC;
+----+--------------+--------------+
| id | combined_num | value_concat |
+----+--------------+--------------+
| 10 | 1100 | kappa-tenth |
| 8 | 880 | theta-eighth |
| 6 | 660 | zeta-sixth |
+----+--------------+--------------+
-- Hash join with filtering on both tables
SELECT
a.value_a, b.value_b, a.num_a, b.num_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
WHERE a.num_a > 500 AND b.num_b < 100
ORDER BY a.num_a DESC;
+---------+---------+-------+-------+
| value_a | value_b | num_a | num_b |
+---------+---------+-------+-------+
| theta | eighth | 800 | 80 |
| zeta | sixth | 600 | 60 |
+---------+---------+-------+-------+
-- Hash join for set operations
SELECT
a."id",
'Both Tables' as source,
a.value_a as value_from_a,
b.value_b as value_from_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
UNION ALL
SELECT
a."id",
'Only Table A' as source,
a.value_a,
NULL as value_from_b
FROM large_table_a a
LEFT JOIN large_table_b b ON a."id" = b."id"
WHERE b."id" IS NULL
ORDER BY "id", source;
+----+--------------+--------------+--------------+
| id | source | value_from_a | value_from_b |
+----+--------------+--------------+--------------+
| 1 | Only Table A | alpha | |
| 2 | Both Tables | beta | second |
| 3 | Only Table A | gamma | |
| 4 | Both Tables | delta | fourth |
| 5 | Only Table A | epsilon | |
| 6 | Both Tables | zeta | sixth |
| 7 | Only Table A | eta | |
| 8 | Both Tables | theta | eighth |
| 9 | Only Table A | iota | |
| 10 | Both Tables | kappa | tenth |
+----+--------------+--------------+--------------+
DROP TABLE large_table_a;
Affected Rows: 0
DROP TABLE large_table_b;
Affected Rows: 0

View File

@@ -0,0 +1,78 @@
-- Migrated from DuckDB test: test/sql/join/ hash join tests
-- Tests complex hash join scenarios
CREATE TABLE large_table_a("id" INTEGER, value_a VARCHAR, num_a INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE large_table_b("id" INTEGER, value_b VARCHAR, num_b INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO large_table_a VALUES
(1, 'alpha', 100, 1000), (2, 'beta', 200, 2000), (3, 'gamma', 300, 3000),
(4, 'delta', 400, 4000), (5, 'epsilon', 500, 5000), (6, 'zeta', 600, 6000),
(7, 'eta', 700, 7000), (8, 'theta', 800, 8000), (9, 'iota', 900, 9000),
(10, 'kappa', 1000, 10000);
INSERT INTO large_table_b VALUES
(2, 'second', 20, 1000), (4, 'fourth', 40, 2000), (6, 'sixth', 60, 3000),
(8, 'eighth', 80, 4000), (10, 'tenth', 100, 5000), (12, 'twelfth', 120, 6000),
(14, 'fourteenth', 140, 7000), (16, 'sixteenth', 160, 8000);
-- Hash join with exact match
SELECT
a."id", a.value_a, a.num_a, b.value_b, b.num_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
ORDER BY a."id";
-- Hash join with multiple key conditions
SELECT
a."id", a.value_a, b.value_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id" AND a.num_a > b.num_b * 5
ORDER BY a."id";
-- Hash join with aggregation on both sides
SELECT
joined_data."id",
joined_data.combined_num,
joined_data.value_concat
FROM (
SELECT
a."id",
a.num_a + b.num_b as combined_num,
a.value_a || '-' || b.value_b as value_concat
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
) joined_data
WHERE joined_data.combined_num > 500
ORDER BY joined_data.combined_num DESC;
-- Hash join with filtering on both tables
SELECT
a.value_a, b.value_b, a.num_a, b.num_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
WHERE a.num_a > 500 AND b.num_b < 100
ORDER BY a.num_a DESC;
-- Hash join for set operations
SELECT
a."id",
'Both Tables' as source,
a.value_a as value_from_a,
b.value_b as value_from_b
FROM large_table_a a
INNER JOIN large_table_b b ON a."id" = b."id"
UNION ALL
SELECT
a."id",
'Only Table A' as source,
a.value_a,
NULL as value_from_b
FROM large_table_a a
LEFT JOIN large_table_b b ON a."id" = b."id"
WHERE b."id" IS NULL
ORDER BY "id", source;
DROP TABLE large_table_a;
DROP TABLE large_table_b;

View File

@@ -0,0 +1,79 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_range_join.test
-- Tests inequality JOIN conditions
CREATE TABLE events("id" INTEGER, event_time INTEGER, duration INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE time_ranges(start_time INTEGER, end_time INTEGER, range_name VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO events VALUES (1, 10, 5, 1000), (2, 25, 3, 2000), (3, 45, 8, 3000);
Affected Rows: 3
INSERT INTO time_ranges VALUES (0, 20, 'Early', 4000), (20, 40, 'Mid', 5000), (40, 60, 'Late', 6000);
Affected Rows: 3
-- Range join using BETWEEN
SELECT e."id", e.event_time, t.range_name
FROM events e JOIN time_ranges t ON e.event_time BETWEEN t.start_time AND t.end_time
ORDER BY e."id";
+----+------------+------------+
| id | event_time | range_name |
+----+------------+------------+
| 1 | 10 | Early |
| 2 | 25 | Mid |
| 3 | 45 | Late |
+----+------------+------------+
-- Inequality join conditions
SELECT e."id", e.event_time, e.duration, t.range_name
FROM events e JOIN time_ranges t ON e.event_time >= t.start_time AND e.event_time < t.end_time
ORDER BY e."id";
+----+------------+----------+------------+
| id | event_time | duration | range_name |
+----+------------+----------+------------+
| 1 | 10 | 5 | Early |
| 2 | 25 | 3 | Mid |
| 3 | 45 | 8 | Late |
+----+------------+----------+------------+
-- Join with overlap condition
SELECT e."id", t.range_name
FROM events e JOIN time_ranges t ON
e.event_time < t.end_time AND (e.event_time + e.duration) > t.start_time
ORDER BY e."id", t.start_time;
+----+------------+
| id | range_name |
+----+------------+
| 1 | Early |
| 2 | Mid |
| 3 | Late |
+----+------------+
-- Self join with inequality
SELECT e1."id" as id1, e2."id" as id2, e1.event_time, e2.event_time
FROM events e1 JOIN events e2 ON e1.event_time < e2.event_time
ORDER BY e1."id", e2."id";
+-----+-----+------------+------------+
| id1 | id2 | event_time | event_time |
+-----+-----+------------+------------+
| 1 | 2 | 10 | 25 |
| 1 | 3 | 10 | 45 |
| 2 | 3 | 25 | 45 |
+-----+-----+------------+------------+
DROP TABLE time_ranges;
Affected Rows: 0
DROP TABLE events;
Affected Rows: 0

View File

@@ -0,0 +1,35 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_range_join.test
-- Tests inequality JOIN conditions
CREATE TABLE events("id" INTEGER, event_time INTEGER, duration INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE time_ranges(start_time INTEGER, end_time INTEGER, range_name VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO events VALUES (1, 10, 5, 1000), (2, 25, 3, 2000), (3, 45, 8, 3000);
INSERT INTO time_ranges VALUES (0, 20, 'Early', 4000), (20, 40, 'Mid', 5000), (40, 60, 'Late', 6000);
-- Range join using BETWEEN
SELECT e."id", e.event_time, t.range_name
FROM events e JOIN time_ranges t ON e.event_time BETWEEN t.start_time AND t.end_time
ORDER BY e."id";
-- Inequality join conditions
SELECT e."id", e.event_time, e.duration, t.range_name
FROM events e JOIN time_ranges t ON e.event_time >= t.start_time AND e.event_time < t.end_time
ORDER BY e."id";
-- Join with overlap condition
SELECT e."id", t.range_name
FROM events e JOIN time_ranges t ON
e.event_time < t.end_time AND (e.event_time + e.duration) > t.start_time
ORDER BY e."id", t.start_time;
-- Self join with inequality
SELECT e1."id" as id1, e2."id" as id2, e1.event_time, e2.event_time
FROM events e1 JOIN events e2 ON e1.event_time < e2.event_time
ORDER BY e1."id", e2."id";
DROP TABLE time_ranges;
DROP TABLE events;

View File

@@ -0,0 +1,167 @@
-- Migrated from DuckDB test: test/sql/join/iejoin/ inequality join tests
-- Tests inequality join conditions
CREATE TABLE time_events(event_id INTEGER, event_time TIMESTAMP, event_type VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE time_windows(window_id INTEGER, start_time TIMESTAMP, end_time TIMESTAMP, window_name VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO time_events VALUES
(1, '2023-01-01 10:15:00', 'login', 1000),
(2, '2023-01-01 10:30:00', 'purchase', 2000),
(3, '2023-01-01 10:45:00', 'logout', 3000),
(4, '2023-01-01 11:05:00', 'login', 4000),
(5, '2023-01-01 11:20:00', 'view', 5000),
(6, '2023-01-01 11:35:00', 'purchase', 6000);
Affected Rows: 6
INSERT INTO time_windows VALUES
(1, '2023-01-01 10:00:00', '2023-01-01 10:30:00', 'Morning Early', 1000),
(2, '2023-01-01 10:30:00', '2023-01-01 11:00:00', 'Morning Late', 2000),
(3, '2023-01-01 11:00:00', '2023-01-01 11:30:00', 'Noon Early', 3000),
(4, '2023-01-01 11:30:00', '2023-01-01 12:00:00', 'Noon Late', 4000);
Affected Rows: 4
-- Range join: events within time windows
SELECT
e.event_id, e.event_time, e.event_type, w.window_name
FROM time_events e
INNER JOIN time_windows w
ON e.event_time >= w.start_time AND e.event_time < w.end_time
ORDER BY e.event_time;
+----------+---------------------+------------+---------------+
| event_id | event_time | event_type | window_name |
+----------+---------------------+------------+---------------+
| 1 | 2023-01-01T10:15:00 | login | Morning Early |
| 2 | 2023-01-01T10:30:00 | purchase | Morning Late |
| 3 | 2023-01-01T10:45:00 | logout | Morning Late |
| 4 | 2023-01-01T11:05:00 | login | Noon Early |
| 5 | 2023-01-01T11:20:00 | view | Noon Early |
| 6 | 2023-01-01T11:35:00 | purchase | Noon Late |
+----------+---------------------+------------+---------------+
-- Inequality join with additional conditions
SELECT
e.event_id, e.event_type, w.window_name
FROM time_events e
INNER JOIN time_windows w
ON e.event_time >= w.start_time
AND e.event_time < w.end_time
AND e.event_type = 'purchase'
ORDER BY e.event_time;
+----------+------------+--------------+
| event_id | event_type | window_name |
+----------+------------+--------------+
| 2 | purchase | Morning Late |
| 6 | purchase | Noon Late |
+----------+------------+--------------+
-- Cross-time analysis with inequality joins
SELECT
e1.event_id as first_event, e2.event_id as second_event,
e1.event_type as first_type, e2.event_type as second_type,
e2.event_time - e1.event_time as time_diff
FROM time_events e1
INNER JOIN time_events e2
ON e1.event_time < e2.event_time
AND e2.event_time - e1.event_time <= INTERVAL '30 minutes'
ORDER BY e1.event_time, e2.event_time;
+-------------+--------------+------------+-------------+-----------+
| first_event | second_event | first_type | second_type | time_diff |
+-------------+--------------+------------+-------------+-----------+
| 1 | 2 | login | purchase | PT900S |
| 1 | 3 | login | logout | PT1800S |
| 2 | 3 | purchase | logout | PT900S |
| 3 | 4 | logout | login | PT1200S |
| 4 | 5 | login | view | PT900S |
| 4 | 6 | login | purchase | PT1800S |
| 5 | 6 | view | purchase | PT900S |
+-------------+--------------+------------+-------------+-----------+
CREATE TABLE price_history(item_id INTEGER, price DOUBLE, effective_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE orders_ineq(order_id INTEGER, item_id INTEGER, order_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO price_history VALUES
(1, 100.00, '2023-01-01', 1000), (1, 110.00, '2023-01-15', 2000),
(2, 50.00, '2023-01-01', 3000), (2, 55.00, '2023-01-20', 4000);
Affected Rows: 4
INSERT INTO orders_ineq VALUES
(1, 1, '2023-01-10', 1000), (2, 1, '2023-01-20', 2000),
(3, 2, '2023-01-05', 3000), (4, 2, '2023-01-25', 4000);
Affected Rows: 4
-- Historical price lookup with inequality join
SELECT
o.order_id, o.order_date, p.price, p.effective_date
FROM orders_ineq o
INNER JOIN price_history p
ON o.item_id = p.item_id
AND o.order_date >= p.effective_date
ORDER BY o.order_id;
+----------+------------+-------+----------------+
| order_id | order_date | price | effective_date |
+----------+------------+-------+----------------+
| 1 | 2023-01-10 | 100.0 | 2023-01-01 |
| 2 | 2023-01-20 | 100.0 | 2023-01-01 |
| 2 | 2023-01-20 | 110.0 | 2023-01-15 |
| 3 | 2023-01-05 | 50.0 | 2023-01-01 |
| 4 | 2023-01-25 | 50.0 | 2023-01-01 |
| 4 | 2023-01-25 | 55.0 | 2023-01-20 |
+----------+------------+-------+----------------+
-- Latest price before order date
SELECT
o.order_id, o.order_date, latest_price.price
FROM orders_ineq o
INNER JOIN (
SELECT
item_id,
price,
effective_date,
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY effective_date DESC) as rn
FROM price_history
) latest_price
ON o.item_id = latest_price.item_id
AND o.order_date >= latest_price.effective_date
AND latest_price.rn = 1
ORDER BY o.order_id;
+----------+------------+-------+
| order_id | order_date | price |
+----------+------------+-------+
| 2 | 2023-01-20 | 110.0 |
| 4 | 2023-01-25 | 55.0 |
+----------+------------+-------+
DROP TABLE time_events;
Affected Rows: 0
DROP TABLE time_windows;
Affected Rows: 0
DROP TABLE price_history;
Affected Rows: 0
DROP TABLE orders_ineq;
Affected Rows: 0

View File

@@ -0,0 +1,94 @@
-- Migrated from DuckDB test: test/sql/join/iejoin/ inequality join tests
-- Tests inequality join conditions
CREATE TABLE time_events(event_id INTEGER, event_time TIMESTAMP, event_type VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE time_windows(window_id INTEGER, start_time TIMESTAMP, end_time TIMESTAMP, window_name VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO time_events VALUES
(1, '2023-01-01 10:15:00', 'login', 1000),
(2, '2023-01-01 10:30:00', 'purchase', 2000),
(3, '2023-01-01 10:45:00', 'logout', 3000),
(4, '2023-01-01 11:05:00', 'login', 4000),
(5, '2023-01-01 11:20:00', 'view', 5000),
(6, '2023-01-01 11:35:00', 'purchase', 6000);
INSERT INTO time_windows VALUES
(1, '2023-01-01 10:00:00', '2023-01-01 10:30:00', 'Morning Early', 1000),
(2, '2023-01-01 10:30:00', '2023-01-01 11:00:00', 'Morning Late', 2000),
(3, '2023-01-01 11:00:00', '2023-01-01 11:30:00', 'Noon Early', 3000),
(4, '2023-01-01 11:30:00', '2023-01-01 12:00:00', 'Noon Late', 4000);
-- Range join: events within time windows
SELECT
e.event_id, e.event_time, e.event_type, w.window_name
FROM time_events e
INNER JOIN time_windows w
ON e.event_time >= w.start_time AND e.event_time < w.end_time
ORDER BY e.event_time;
-- Inequality join with additional conditions
SELECT
e.event_id, e.event_type, w.window_name
FROM time_events e
INNER JOIN time_windows w
ON e.event_time >= w.start_time
AND e.event_time < w.end_time
AND e.event_type = 'purchase'
ORDER BY e.event_time;
-- Cross-time analysis with inequality joins
SELECT
e1.event_id as first_event, e2.event_id as second_event,
e1.event_type as first_type, e2.event_type as second_type,
e2.event_time - e1.event_time as time_diff
FROM time_events e1
INNER JOIN time_events e2
ON e1.event_time < e2.event_time
AND e2.event_time - e1.event_time <= INTERVAL '30 minutes'
ORDER BY e1.event_time, e2.event_time;
CREATE TABLE price_history(item_id INTEGER, price DOUBLE, effective_date DATE, ts TIMESTAMP TIME INDEX);
CREATE TABLE orders_ineq(order_id INTEGER, item_id INTEGER, order_date DATE, ts TIMESTAMP TIME INDEX);
INSERT INTO price_history VALUES
(1, 100.00, '2023-01-01', 1000), (1, 110.00, '2023-01-15', 2000),
(2, 50.00, '2023-01-01', 3000), (2, 55.00, '2023-01-20', 4000);
INSERT INTO orders_ineq VALUES
(1, 1, '2023-01-10', 1000), (2, 1, '2023-01-20', 2000),
(3, 2, '2023-01-05', 3000), (4, 2, '2023-01-25', 4000);
-- Historical price lookup with inequality join
SELECT
o.order_id, o.order_date, p.price, p.effective_date
FROM orders_ineq o
INNER JOIN price_history p
ON o.item_id = p.item_id
AND o.order_date >= p.effective_date
ORDER BY o.order_id;
-- Latest price before order date
SELECT
o.order_id, o.order_date, latest_price.price
FROM orders_ineq o
INNER JOIN (
SELECT
item_id,
price,
effective_date,
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY effective_date DESC) as rn
FROM price_history
) latest_price
ON o.item_id = latest_price.item_id
AND o.order_date >= latest_price.effective_date
AND latest_price.rn = 1
ORDER BY o.order_id;
DROP TABLE time_events;
DROP TABLE time_windows;
DROP TABLE price_history;
DROP TABLE orders_ineq;

View File

@@ -0,0 +1,167 @@
-- Migrated from DuckDB test: test/sql/join/inner/ advanced tests
-- Tests advanced inner join patterns
CREATE TABLE customers(cust_id INTEGER, cust_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE orders(order_id INTEGER, cust_id INTEGER, order_date DATE, amount DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE order_items(item_id INTEGER, order_id INTEGER, product VARCHAR, quantity INTEGER, price DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO customers VALUES
(1, 'John', 'NYC', 1000), (2, 'Jane', 'LA', 2000), (3, 'Bob', 'Chicago', 3000), (4, 'Alice', 'NYC', 4000);
Affected Rows: 4
INSERT INTO orders VALUES
(101, 1, '2023-01-01', 250.00, 1000), (102, 2, '2023-01-02', 180.00, 2000),
(103, 1, '2023-01-03', 420.00, 3000), (104, 3, '2023-01-04', 95.00, 4000),
(105, 4, '2023-01-05', 310.00, 5000);
Affected Rows: 5
INSERT INTO order_items VALUES
(1, 101, 'Widget', 2, 125.00, 1000), (2, 101, 'Gadget', 1, 0.00, 2000),
(3, 102, 'Tool', 3, 60.00, 3000), (4, 103, 'Device', 1, 420.00, 4000),
(5, 104, 'Part', 5, 19.00, 5000), (6, 105, 'Component', 2, 155.00, 6000);
Affected Rows: 6
-- Multi-table inner join
SELECT
c.cust_name, c.city, o.order_id, o.order_date, o.amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
ORDER BY o.order_date, c.cust_name;
+-----------+---------+----------+------------+--------+
| cust_name | city | order_id | order_date | amount |
+-----------+---------+----------+------------+--------+
| John | NYC | 101 | 2023-01-01 | 250.0 |
| Jane | LA | 102 | 2023-01-02 | 180.0 |
| John | NYC | 103 | 2023-01-03 | 420.0 |
| Bob | Chicago | 104 | 2023-01-04 | 95.0 |
| Alice | NYC | 105 | 2023-01-05 | 310.0 |
+-----------+---------+----------+------------+--------+
-- Three-way inner join
SELECT
c.cust_name, o.order_id, oi.product, oi.quantity, oi.price
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
ORDER BY c.cust_name, o.order_id, oi.product;
+-----------+----------+-----------+----------+-------+
| cust_name | order_id | product | quantity | price |
+-----------+----------+-----------+----------+-------+
| Alice | 105 | Component | 2 | 155.0 |
| Bob | 104 | Part | 5 | 19.0 |
| Jane | 102 | Tool | 3 | 60.0 |
| John | 101 | Gadget | 1 | 0.0 |
| John | 101 | Widget | 2 | 125.0 |
| John | 103 | Device | 1 | 420.0 |
+-----------+----------+-----------+----------+-------+
-- Inner join with complex conditions
SELECT
c.cust_name, o.order_id, o.amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id AND o.amount > 200.00
ORDER BY o.amount DESC;
+-----------+----------+--------+
| cust_name | order_id | amount |
+-----------+----------+--------+
| John | 103 | 420.0 |
| Alice | 105 | 310.0 |
| John | 101 | 250.0 |
+-----------+----------+--------+
-- Inner join with aggregation
SELECT
c.city,
COUNT(o.order_id) as total_orders,
SUM(o.amount) as total_amount,
AVG(o.amount) as avg_order_amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
GROUP BY c.city
ORDER BY total_amount DESC;
+---------+--------------+--------------+-------------------+
| city | total_orders | total_amount | avg_order_amount |
+---------+--------------+--------------+-------------------+
| NYC | 3 | 980.0 | 326.6666666666667 |
| LA | 1 | 180.0 | 180.0 |
| Chicago | 1 | 95.0 | 95.0 |
+---------+--------------+--------------+-------------------+
-- Self join
SELECT
o1.order_id as order1, o2.order_id as order2, o1.amount, o2.amount
FROM orders o1
INNER JOIN orders o2 ON o1.cust_id = o2.cust_id AND o1.order_id < o2.order_id
ORDER BY o1.order_id, o2.order_id;
+--------+--------+--------+--------+
| order1 | order2 | amount | amount |
+--------+--------+--------+--------+
| 101 | 103 | 250.0 | 420.0 |
+--------+--------+--------+--------+
-- Join with subquery
SELECT
c.cust_name, high_orders.total_amount
FROM customers c
INNER JOIN (
SELECT cust_id, SUM(amount) as total_amount
FROM orders
GROUP BY cust_id
HAVING SUM(amount) > 300
) high_orders ON c.cust_id = high_orders.cust_id
ORDER BY high_orders.total_amount DESC;
+-----------+--------------+
| cust_name | total_amount |
+-----------+--------------+
| John | 670.0 |
| Alice | 310.0 |
+-----------+--------------+
-- Join with window functions
SELECT
c.cust_name,
o.order_id,
o.amount,
ROW_NUMBER() OVER (PARTITION BY c.cust_id ORDER BY o.order_date) as order_sequence
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
ORDER BY c.cust_name, order_sequence;
+-----------+----------+--------+----------------+
| cust_name | order_id | amount | order_sequence |
+-----------+----------+--------+----------------+
| Alice | 105 | 310.0 | 1 |
| Bob | 104 | 95.0 | 1 |
| Jane | 102 | 180.0 | 1 |
| John | 101 | 250.0 | 1 |
| John | 103 | 420.0 | 2 |
+-----------+----------+--------+----------------+
DROP TABLE customers;
Affected Rows: 0
DROP TABLE orders;
Affected Rows: 0
DROP TABLE order_items;
Affected Rows: 0

View File

@@ -0,0 +1,87 @@
-- Migrated from DuckDB test: test/sql/join/inner/ advanced tests
-- Tests advanced inner join patterns
CREATE TABLE customers(cust_id INTEGER, cust_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE orders(order_id INTEGER, cust_id INTEGER, order_date DATE, amount DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE order_items(item_id INTEGER, order_id INTEGER, product VARCHAR, quantity INTEGER, price DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO customers VALUES
(1, 'John', 'NYC', 1000), (2, 'Jane', 'LA', 2000), (3, 'Bob', 'Chicago', 3000), (4, 'Alice', 'NYC', 4000);
INSERT INTO orders VALUES
(101, 1, '2023-01-01', 250.00, 1000), (102, 2, '2023-01-02', 180.00, 2000),
(103, 1, '2023-01-03', 420.00, 3000), (104, 3, '2023-01-04', 95.00, 4000),
(105, 4, '2023-01-05', 310.00, 5000);
INSERT INTO order_items VALUES
(1, 101, 'Widget', 2, 125.00, 1000), (2, 101, 'Gadget', 1, 0.00, 2000),
(3, 102, 'Tool', 3, 60.00, 3000), (4, 103, 'Device', 1, 420.00, 4000),
(5, 104, 'Part', 5, 19.00, 5000), (6, 105, 'Component', 2, 155.00, 6000);
-- Multi-table inner join
SELECT
c.cust_name, c.city, o.order_id, o.order_date, o.amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
ORDER BY o.order_date, c.cust_name;
-- Three-way inner join
SELECT
c.cust_name, o.order_id, oi.product, oi.quantity, oi.price
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
ORDER BY c.cust_name, o.order_id, oi.product;
-- Inner join with complex conditions
SELECT
c.cust_name, o.order_id, o.amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id AND o.amount > 200.00
ORDER BY o.amount DESC;
-- Inner join with aggregation
SELECT
c.city,
COUNT(o.order_id) as total_orders,
SUM(o.amount) as total_amount,
AVG(o.amount) as avg_order_amount
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
GROUP BY c.city
ORDER BY total_amount DESC;
-- Self join
SELECT
o1.order_id as order1, o2.order_id as order2, o1.amount, o2.amount
FROM orders o1
INNER JOIN orders o2 ON o1.cust_id = o2.cust_id AND o1.order_id < o2.order_id
ORDER BY o1.order_id, o2.order_id;
-- Join with subquery
SELECT
c.cust_name, high_orders.total_amount
FROM customers c
INNER JOIN (
SELECT cust_id, SUM(amount) as total_amount
FROM orders
GROUP BY cust_id
HAVING SUM(amount) > 300
) high_orders ON c.cust_id = high_orders.cust_id
ORDER BY high_orders.total_amount DESC;
-- Join with window functions
SELECT
c.cust_name,
o.order_id,
o.amount,
ROW_NUMBER() OVER (PARTITION BY c.cust_id ORDER BY o.order_date) as order_sequence
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
ORDER BY c.cust_name, order_sequence;
DROP TABLE customers;
DROP TABLE orders;
DROP TABLE order_items;

View File

@@ -0,0 +1,162 @@
-- Migrated from DuckDB test: test/sql/join/ complex condition tests
-- Tests complex join conditions and predicates
CREATE TABLE sales_reps(rep_id INTEGER, "name" VARCHAR, region VARCHAR, quota INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE customer_accounts(account_id INTEGER, account_name VARCHAR, region VARCHAR, rep_id INTEGER, revenue INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO sales_reps VALUES
(1, 'Tom', 'North', 100000, 1000), (2, 'Sarah', 'South', 150000, 2000),
(3, 'Mike', 'East', 120000, 3000), (4, 'Lisa', 'West', 180000, 4000);
Affected Rows: 4
INSERT INTO customer_accounts VALUES
(101, 'TechCorp', 'North', 1, 85000, 1000), (102, 'DataInc', 'South', 2, 195000, 2000),
(103, 'CloudSys', 'North', 1, 110000, 3000), (104, 'NetSoft', 'East', 3, 75000, 4000),
(105, 'WebCo', 'West', 4, 225000, 5000), (106, 'AppDev', 'South', 2, 140000, 6000);
Affected Rows: 6
-- Join with multiple conditions
SELECT
sr."name" as rep_name, ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id AND sr.region = ca.region
ORDER BY sr.rep_id, ca.revenue DESC;
+----------+--------------+---------+
| rep_name | account_name | revenue |
+----------+--------------+---------+
| Tom | CloudSys | 110000 |
| Tom | TechCorp | 85000 |
| Sarah | DataInc | 195000 |
| Sarah | AppDev | 140000 |
| Mike | NetSoft | 75000 |
| Lisa | WebCo | 225000 |
+----------+--------------+---------+
-- Join with inequality conditions
SELECT
sr."name", sr.quota, ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id AND ca.revenue < sr.quota
ORDER BY sr.rep_id, ca.revenue;
+-------+--------+--------------+---------+
| name | quota | account_name | revenue |
+-------+--------+--------------+---------+
| Tom | 100000 | TechCorp | 85000 |
| Sarah | 150000 | AppDev | 140000 |
| Mike | 120000 | NetSoft | 75000 |
+-------+--------+--------------+---------+
-- Join with range conditions
SELECT
sr."name", ca.account_name, ca.revenue, sr.quota
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND ca.revenue BETWEEN sr.quota * 0.5 AND sr.quota * 1.5
ORDER BY sr.rep_id, ca.revenue;
+-------+--------------+---------+--------+
| name | account_name | revenue | quota |
+-------+--------------+---------+--------+
| Tom | TechCorp | 85000 | 100000 |
| Tom | CloudSys | 110000 | 100000 |
| Sarah | AppDev | 140000 | 150000 |
| Sarah | DataInc | 195000 | 150000 |
| Mike | NetSoft | 75000 | 120000 |
| Lisa | WebCo | 225000 | 180000 |
+-------+--------------+---------+--------+
-- Join with CASE in conditions
SELECT
sr."name", ca.account_name, ca.revenue,
CASE WHEN ca.revenue >= sr.quota THEN 'Met Quota' ELSE 'Below Quota' END as performance
FROM sales_reps sr
INNER JOIN customer_accounts ca ON sr.rep_id = ca.rep_id
ORDER BY sr.rep_id, ca.revenue DESC;
+-------+--------------+---------+-------------+
| name | account_name | revenue | performance |
+-------+--------------+---------+-------------+
| Tom | CloudSys | 110000 | Met Quota |
| Tom | TechCorp | 85000 | Below Quota |
| Sarah | DataInc | 195000 | Met Quota |
| Sarah | AppDev | 140000 | Below Quota |
| Mike | NetSoft | 75000 | Below Quota |
| Lisa | WebCo | 225000 | Met Quota |
+-------+--------------+---------+-------------+
-- Join with expression conditions
SELECT
sr."name", ca.account_name,
ca.revenue, sr.quota,
ca.revenue - sr.quota as quota_diff
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND UPPER(sr.region) = UPPER(ca.region)
ORDER BY quota_diff DESC, sr."name" ASC;
+-------+--------------+---------+--------+------------+
| name | account_name | revenue | quota | quota_diff |
+-------+--------------+---------+--------+------------+
| Lisa | WebCo | 225000 | 180000 | 45000 |
| Sarah | DataInc | 195000 | 150000 | 45000 |
| Tom | CloudSys | 110000 | 100000 | 10000 |
| Sarah | AppDev | 140000 | 150000 | -10000 |
| Tom | TechCorp | 85000 | 100000 | -15000 |
| Mike | NetSoft | 75000 | 120000 | -45000 |
+-------+--------------+---------+--------+------------+
-- Join with string pattern conditions
SELECT
sr."name", ca.account_name
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND ca.account_name LIKE '%Corp%'
ORDER BY sr."name";
+------+--------------+
| name | account_name |
+------+--------------+
| Tom | TechCorp |
+------+--------------+
-- Complex nested join conditions
SELECT
sr."name", ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca ON (
sr.rep_id = ca.rep_id
AND (ca.revenue > 100000 OR sr.quota < 130000)
AND sr.region IN ('North', 'South')
)
ORDER BY ca.revenue DESC;
+-------+--------------+---------+
| name | account_name | revenue |
+-------+--------------+---------+
| Sarah | DataInc | 195000 |
| Sarah | AppDev | 140000 |
| Tom | CloudSys | 110000 |
| Tom | TechCorp | 85000 |
+-------+--------------+---------+
DROP TABLE sales_reps;
Affected Rows: 0
DROP TABLE customer_accounts;
Affected Rows: 0

View File

@@ -0,0 +1,83 @@
-- Migrated from DuckDB test: test/sql/join/ complex condition tests
-- Tests complex join conditions and predicates
CREATE TABLE sales_reps(rep_id INTEGER, "name" VARCHAR, region VARCHAR, quota INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE customer_accounts(account_id INTEGER, account_name VARCHAR, region VARCHAR, rep_id INTEGER, revenue INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO sales_reps VALUES
(1, 'Tom', 'North', 100000, 1000), (2, 'Sarah', 'South', 150000, 2000),
(3, 'Mike', 'East', 120000, 3000), (4, 'Lisa', 'West', 180000, 4000);
INSERT INTO customer_accounts VALUES
(101, 'TechCorp', 'North', 1, 85000, 1000), (102, 'DataInc', 'South', 2, 195000, 2000),
(103, 'CloudSys', 'North', 1, 110000, 3000), (104, 'NetSoft', 'East', 3, 75000, 4000),
(105, 'WebCo', 'West', 4, 225000, 5000), (106, 'AppDev', 'South', 2, 140000, 6000);
-- Join with multiple conditions
SELECT
sr."name" as rep_name, ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id AND sr.region = ca.region
ORDER BY sr.rep_id, ca.revenue DESC;
-- Join with inequality conditions
SELECT
sr."name", sr.quota, ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id AND ca.revenue < sr.quota
ORDER BY sr.rep_id, ca.revenue;
-- Join with range conditions
SELECT
sr."name", ca.account_name, ca.revenue, sr.quota
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND ca.revenue BETWEEN sr.quota * 0.5 AND sr.quota * 1.5
ORDER BY sr.rep_id, ca.revenue;
-- Join with CASE in conditions
SELECT
sr."name", ca.account_name, ca.revenue,
CASE WHEN ca.revenue >= sr.quota THEN 'Met Quota' ELSE 'Below Quota' END as performance
FROM sales_reps sr
INNER JOIN customer_accounts ca ON sr.rep_id = ca.rep_id
ORDER BY sr.rep_id, ca.revenue DESC;
-- Join with expression conditions
SELECT
sr."name", ca.account_name,
ca.revenue, sr.quota,
ca.revenue - sr.quota as quota_diff
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND UPPER(sr.region) = UPPER(ca.region)
ORDER BY quota_diff DESC, sr."name" ASC;
-- Join with string pattern conditions
SELECT
sr."name", ca.account_name
FROM sales_reps sr
INNER JOIN customer_accounts ca
ON sr.rep_id = ca.rep_id
AND ca.account_name LIKE '%Corp%'
ORDER BY sr."name";
-- Complex nested join conditions
SELECT
sr."name", ca.account_name, ca.revenue
FROM sales_reps sr
INNER JOIN customer_accounts ca ON (
sr.rep_id = ca.rep_id
AND (ca.revenue > 100000 OR sr.quota < 130000)
AND sr.region IN ('North', 'South')
)
ORDER BY ca.revenue DESC;
DROP TABLE sales_reps;
DROP TABLE customer_accounts;

View File

@@ -0,0 +1,53 @@
-- Tests joins with DISTINCT operations
CREATE TABLE products_dist(prod_id INTEGER, prod_name VARCHAR, category VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE sales_dist(sale_id INTEGER, prod_id INTEGER, customer VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO products_dist VALUES (1, 'Widget', 'Tools', 1000), (2, 'Gadget', 'Electronics', 2000);
Affected Rows: 2
INSERT INTO sales_dist VALUES (1, 1, 'Alice', 1000), (2, 1, 'Bob', 2000), (3, 2, 'Alice', 3000), (4, 1, 'Alice', 4000);
Affected Rows: 4
SELECT DISTINCT p.category FROM products_dist p INNER JOIN sales_dist s ON p.prod_id = s.prod_id ORDER BY p.category;
+-------------+
| category |
+-------------+
| Electronics |
| Tools |
+-------------+
SELECT DISTINCT s.customer, p.category FROM sales_dist s INNER JOIN products_dist p ON s.prod_id = p.prod_id ORDER BY s.customer, p.category;
+----------+-------------+
| customer | category |
+----------+-------------+
| Alice | Electronics |
| Alice | Tools |
| Bob | Tools |
+----------+-------------+
SELECT p.prod_name, COUNT(DISTINCT s.customer) as unique_customers FROM products_dist p LEFT JOIN sales_dist s ON p.prod_id = s.prod_id GROUP BY p.prod_id, p.prod_name ORDER BY unique_customers DESC;
+-----------+------------------+
| prod_name | unique_customers |
+-----------+------------------+
| Widget | 2 |
| Gadget | 1 |
+-----------+------------------+
DROP TABLE products_dist;
Affected Rows: 0
DROP TABLE sales_dist;
Affected Rows: 0

View File

@@ -0,0 +1,18 @@
-- Tests joins with DISTINCT operations
CREATE TABLE products_dist(prod_id INTEGER, prod_name VARCHAR, category VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE sales_dist(sale_id INTEGER, prod_id INTEGER, customer VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO products_dist VALUES (1, 'Widget', 'Tools', 1000), (2, 'Gadget', 'Electronics', 2000);
INSERT INTO sales_dist VALUES (1, 1, 'Alice', 1000), (2, 1, 'Bob', 2000), (3, 2, 'Alice', 3000), (4, 1, 'Alice', 4000);
SELECT DISTINCT p.category FROM products_dist p INNER JOIN sales_dist s ON p.prod_id = s.prod_id ORDER BY p.category;
SELECT DISTINCT s.customer, p.category FROM sales_dist s INNER JOIN products_dist p ON s.prod_id = p.prod_id ORDER BY s.customer, p.category;
SELECT p.prod_name, COUNT(DISTINCT s.customer) as unique_customers FROM products_dist p LEFT JOIN sales_dist s ON p.prod_id = s.prod_id GROUP BY p.prod_id, p.prod_name ORDER BY unique_customers DESC;
DROP TABLE products_dist;
DROP TABLE sales_dist;

View File

@@ -0,0 +1,62 @@
-- Tests join edge cases and special scenarios
CREATE TABLE empty_table("id" INTEGER, "value" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE single_row("id" INTEGER, "data" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE duplicate_keys("id" INTEGER, "description" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO single_row VALUES (1, 'only_row', 1000);
Affected Rows: 1
INSERT INTO duplicate_keys VALUES (1, 'first', 1000), (1, 'second', 2000), (2, 'third', 3000), (2, 'fourth', 4000);
Affected Rows: 4
-- Join with empty table
SELECT s."id", s."data", e."value" FROM single_row s LEFT JOIN empty_table e ON s."id" = e."id" ORDER BY s."id";
+----+----------+-------+
| id | data | value |
+----+----------+-------+
| 1 | only_row | |
+----+----------+-------+
-- Join with duplicate keys
SELECT s."id", s."data", d."description" FROM single_row s LEFT JOIN duplicate_keys d ON s."id" = d."id" ORDER BY d."description";
+----+----------+-------------+
| id | data | description |
+----+----------+-------------+
| 1 | only_row | first |
| 1 | only_row | second |
+----+----------+-------------+
-- Self-join with duplicates
SELECT d1."description" as desc1, d2."description" as desc2 FROM duplicate_keys d1 INNER JOIN duplicate_keys d2 ON d1."id" = d2."id" AND d1.ts < d2.ts ORDER BY d1.ts, d2.ts;
+-------+--------+
| desc1 | desc2 |
+-------+--------+
| first | second |
| third | fourth |
+-------+--------+
DROP TABLE empty_table;
Affected Rows: 0
DROP TABLE single_row;
Affected Rows: 0
DROP TABLE duplicate_keys;
Affected Rows: 0

View File

@@ -0,0 +1,26 @@
-- Tests join edge cases and special scenarios
CREATE TABLE empty_table("id" INTEGER, "value" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE single_row("id" INTEGER, "data" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE duplicate_keys("id" INTEGER, "description" VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO single_row VALUES (1, 'only_row', 1000);
INSERT INTO duplicate_keys VALUES (1, 'first', 1000), (1, 'second', 2000), (2, 'third', 3000), (2, 'fourth', 4000);
-- Join with empty table
SELECT s."id", s."data", e."value" FROM single_row s LEFT JOIN empty_table e ON s."id" = e."id" ORDER BY s."id";
-- Join with duplicate keys
SELECT s."id", s."data", d."description" FROM single_row s LEFT JOIN duplicate_keys d ON s."id" = d."id" ORDER BY d."description";
-- Self-join with duplicates
SELECT d1."description" as desc1, d2."description" as desc2 FROM duplicate_keys d1 INNER JOIN duplicate_keys d2 ON d1."id" = d2."id" AND d1.ts < d2.ts ORDER BY d1.ts, d2.ts;
DROP TABLE empty_table;
DROP TABLE single_row;
DROP TABLE duplicate_keys;

View File

@@ -0,0 +1,51 @@
-- Tests joins with larger data sets
CREATE TABLE log_entries(log_id INTEGER, user_id INTEGER, "action" VARCHAR, timestamp_val BIGINT, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE user_profiles(user_id INTEGER, username VARCHAR, signup_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO log_entries VALUES
(1, 1, 'login', 1700000000, 1000), (2, 1, 'view_page', 1700000060, 2000), (3, 2, 'login', 1700000120, 3000),
(4, 2, 'purchase', 1700000180, 4000), (5, 3, 'login', 1700000240, 5000), (6, 1, 'logout', 1700000300, 6000),
(7, 3, 'view_page', 1700000360, 7000), (8, 2, 'logout', 1700000420, 8000), (9, 3, 'purchase', 1700000480, 9000),
(10, 1, 'view_page', 1700000540, 10000), (11, 2, 'view_page', 1700000600, 11000), (12, 3, 'logout', 1700000660, 12000);
Affected Rows: 12
INSERT INTO user_profiles VALUES
(1, 'alice_user', '2022-01-15', 1000), (2, 'bob_user', '2022-03-20', 2000), (3, 'charlie_user', '2022-06-10', 3000);
Affected Rows: 3
SELECT u.username, COUNT(l.log_id) as activity_count, COUNT(DISTINCT l.action) as unique_actions FROM user_profiles u LEFT JOIN log_entries l ON u.user_id = l.user_id GROUP BY u.user_id, u.username ORDER BY activity_count DESC, u.username DESC;
+--------------+----------------+----------------+
| username | activity_count | unique_actions |
+--------------+----------------+----------------+
| charlie_user | 4 | 4 |
| bob_user | 4 | 4 |
| alice_user | 4 | 3 |
+--------------+----------------+----------------+
SELECT l."action", COUNT(DISTINCT l.user_id) as unique_users, COUNT(*) as total_actions FROM log_entries l INNER JOIN user_profiles u ON l.user_id = u.user_id GROUP BY l."action" ORDER BY total_actions DESC, l."action" ASC;
+-----------+--------------+---------------+
| action | unique_users | total_actions |
+-----------+--------------+---------------+
| view_page | 3 | 4 |
| login | 3 | 3 |
| logout | 3 | 3 |
| purchase | 2 | 2 |
+-----------+--------------+---------------+
DROP TABLE log_entries;
Affected Rows: 0
DROP TABLE user_profiles;
Affected Rows: 0

View File

@@ -0,0 +1,22 @@
-- Tests joins with larger data sets
CREATE TABLE log_entries(log_id INTEGER, user_id INTEGER, "action" VARCHAR, timestamp_val BIGINT, ts TIMESTAMP TIME INDEX);
CREATE TABLE user_profiles(user_id INTEGER, username VARCHAR, signup_date DATE, ts TIMESTAMP TIME INDEX);
INSERT INTO log_entries VALUES
(1, 1, 'login', 1700000000, 1000), (2, 1, 'view_page', 1700000060, 2000), (3, 2, 'login', 1700000120, 3000),
(4, 2, 'purchase', 1700000180, 4000), (5, 3, 'login', 1700000240, 5000), (6, 1, 'logout', 1700000300, 6000),
(7, 3, 'view_page', 1700000360, 7000), (8, 2, 'logout', 1700000420, 8000), (9, 3, 'purchase', 1700000480, 9000),
(10, 1, 'view_page', 1700000540, 10000), (11, 2, 'view_page', 1700000600, 11000), (12, 3, 'logout', 1700000660, 12000);
INSERT INTO user_profiles VALUES
(1, 'alice_user', '2022-01-15', 1000), (2, 'bob_user', '2022-03-20', 2000), (3, 'charlie_user', '2022-06-10', 3000);
SELECT u.username, COUNT(l.log_id) as activity_count, COUNT(DISTINCT l.action) as unique_actions FROM user_profiles u LEFT JOIN log_entries l ON u.user_id = l.user_id GROUP BY u.user_id, u.username ORDER BY activity_count DESC, u.username DESC;
SELECT l."action", COUNT(DISTINCT l.user_id) as unique_users, COUNT(*) as total_actions FROM log_entries l INNER JOIN user_profiles u ON l.user_id = u.user_id GROUP BY l."action" ORDER BY total_actions DESC, l."action" ASC;
DROP TABLE log_entries;
DROP TABLE user_profiles;

View File

@@ -0,0 +1,44 @@
-- Tests lateral join patterns and correlated subqueries
CREATE TABLE departments_lat(dept_id INTEGER, dept_name VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE employees_lat(emp_id INTEGER, dept_id INTEGER, salary INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO departments_lat VALUES (1, 'Engineering', 1000), (2, 'Sales', 2000), (3, 'Marketing', 3000);
Affected Rows: 3
INSERT INTO employees_lat VALUES (1, 1, 75000, 1000), (2, 1, 80000, 2000), (3, 2, 65000, 3000), (4, 2, 70000, 4000), (5, 3, 60000, 5000);
Affected Rows: 5
-- Correlated subquery simulating lateral join behavior
SELECT d.dept_name, top_earners.emp_id, top_earners.salary
FROM departments_lat d
INNER JOIN (
SELECT emp_id, dept_id, salary, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) as rn
FROM employees_lat
) top_earners ON d.dept_id = top_earners.dept_id AND top_earners.rn <= 2
ORDER BY d.dept_id, top_earners.salary DESC;
+-------------+--------+--------+
| dept_name | emp_id | salary |
+-------------+--------+--------+
| Engineering | 2 | 80000 |
| Engineering | 1 | 75000 |
| Sales | 4 | 70000 |
| Sales | 3 | 65000 |
| Marketing | 5 | 60000 |
+-------------+--------+--------+
DROP TABLE departments_lat;
Affected Rows: 0
DROP TABLE employees_lat;
Affected Rows: 0

View File

@@ -0,0 +1,22 @@
-- Tests lateral join patterns and correlated subqueries
CREATE TABLE departments_lat(dept_id INTEGER, dept_name VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE employees_lat(emp_id INTEGER, dept_id INTEGER, salary INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO departments_lat VALUES (1, 'Engineering', 1000), (2, 'Sales', 2000), (3, 'Marketing', 3000);
INSERT INTO employees_lat VALUES (1, 1, 75000, 1000), (2, 1, 80000, 2000), (3, 2, 65000, 3000), (4, 2, 70000, 4000), (5, 3, 60000, 5000);
-- Correlated subquery simulating lateral join behavior
SELECT d.dept_name, top_earners.emp_id, top_earners.salary
FROM departments_lat d
INNER JOIN (
SELECT emp_id, dept_id, salary, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) as rn
FROM employees_lat
) top_earners ON d.dept_id = top_earners.dept_id AND top_earners.rn <= 2
ORDER BY d.dept_id, top_earners.salary DESC;
DROP TABLE departments_lat;
DROP TABLE employees_lat;

View File

@@ -0,0 +1,44 @@
-- Tests joins with mixed data types and conversions
CREATE TABLE numeric_keys(int_key INTEGER, float_key DOUBLE, str_val VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE string_keys(str_key VARCHAR, int_val INTEGER, desc_val VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO numeric_keys VALUES (1, 1.0, 'first', 1000), (2, 2.0, 'second', 2000), (3, 3.0, 'third', 3000);
Affected Rows: 3
INSERT INTO string_keys VALUES ('1', 100, 'hundred', 1000), ('2', 200, 'two_hundred', 2000), ('4', 400, 'four_hundred', 3000);
Affected Rows: 3
SELECT n.int_key, n.str_val, s.int_val, s.desc_val FROM numeric_keys n INNER JOIN string_keys s ON CAST(n.int_key AS VARCHAR) = s.str_key ORDER BY n.int_key;
+---------+---------+---------+-------------+
| int_key | str_val | int_val | desc_val |
+---------+---------+---------+-------------+
| 1 | first | 100 | hundred |
| 2 | second | 200 | two_hundred |
+---------+---------+---------+-------------+
SELECT n.float_key, s.str_key, s.int_val FROM numeric_keys n LEFT JOIN string_keys s ON n.float_key = CAST(s.str_key AS DOUBLE) ORDER BY n.float_key;
+-----------+---------+---------+
| float_key | str_key | int_val |
+-----------+---------+---------+
| 1.0 | 1 | 100 |
| 2.0 | 2 | 200 |
| 3.0 | | |
+-----------+---------+---------+
DROP TABLE numeric_keys;
Affected Rows: 0
DROP TABLE string_keys;
Affected Rows: 0

View File

@@ -0,0 +1,17 @@
-- Tests joins with mixed data types and conversions
CREATE TABLE numeric_keys(int_key INTEGER, float_key DOUBLE, str_val VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE string_keys(str_key VARCHAR, int_val INTEGER, desc_val VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO numeric_keys VALUES (1, 1.0, 'first', 1000), (2, 2.0, 'second', 2000), (3, 3.0, 'third', 3000);
INSERT INTO string_keys VALUES ('1', 100, 'hundred', 1000), ('2', 200, 'two_hundred', 2000), ('4', 400, 'four_hundred', 3000);
SELECT n.int_key, n.str_val, s.int_val, s.desc_val FROM numeric_keys n INNER JOIN string_keys s ON CAST(n.int_key AS VARCHAR) = s.str_key ORDER BY n.int_key;
SELECT n.float_key, s.str_key, s.int_val FROM numeric_keys n LEFT JOIN string_keys s ON n.float_key = CAST(s.str_key AS DOUBLE) ORDER BY n.float_key;
DROP TABLE numeric_keys;
DROP TABLE string_keys;

View File

@@ -0,0 +1,121 @@
-- Migrated from DuckDB test: test/sql/join/ NULL handling tests
-- Tests join behavior with NULL values
CREATE TABLE table_with_nulls("id" INTEGER, "value" VARCHAR, category INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE lookup_table(category INTEGER, cat_name VARCHAR, priority INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO table_with_nulls VALUES
(1, 'item1', 1, 1000), (2, 'item2', NULL, 2000), (3, 'item3', 2, 3000),
(4, 'item4', NULL, 4000), (5, 'item5', 3, 5000), (6, 'item6', 1, 6000);
Affected Rows: 6
INSERT INTO lookup_table VALUES
(1, 'Category A', 1, 1000), (2, 'Category B', 2, 2000), (3, 'Category C', 3, 3000), (NULL, 'Unknown', 0, 4000);
Affected Rows: 4
-- Inner join with NULLs (NULLs won't match)
SELECT t."id", t."value", l.cat_name
FROM table_with_nulls t
INNER JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
+----+-------+------------+
| id | value | cat_name |
+----+-------+------------+
| 1 | item1 | Category A |
| 3 | item3 | Category B |
| 5 | item5 | Category C |
| 6 | item6 | Category A |
+----+-------+------------+
-- Left join with NULLs
SELECT t."id", t."value", t.category, COALESCE(l.cat_name, 'No Category') as category_name
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
+----+-------+----------+---------------+
| id | value | category | category_name |
+----+-------+----------+---------------+
| 1 | item1 | 1 | Category A |
| 2 | item2 | | No Category |
| 3 | item3 | 2 | Category B |
| 4 | item4 | | No Category |
| 5 | item5 | 3 | Category C |
| 6 | item6 | 1 | Category A |
+----+-------+----------+---------------+
-- Join with explicit NULL handling
SELECT
t."id", t."value",
CASE
WHEN t.category IS NULL THEN 'NULL Category'
WHEN l.cat_name IS NULL THEN 'Missing Lookup'
ELSE l.cat_name
END as resolved_category
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
+----+-------+-------------------+
| id | value | resolved_category |
+----+-------+-------------------+
| 1 | item1 | Category A |
| 2 | item2 | NULL Category |
| 3 | item3 | Category B |
| 4 | item4 | NULL Category |
| 5 | item5 | Category C |
| 6 | item6 | Category A |
+----+-------+-------------------+
-- NULL-safe join using COALESCE
SELECT t."id", t."value", l.cat_name
FROM table_with_nulls t
INNER JOIN lookup_table l ON COALESCE(t.category, -1) = COALESCE(l.category, -1)
ORDER BY t."id";
+----+-------+------------+
| id | value | cat_name |
+----+-------+------------+
| 1 | item1 | Category A |
| 2 | item2 | Unknown |
| 3 | item3 | Category B |
| 4 | item4 | Unknown |
| 5 | item5 | Category C |
| 6 | item6 | Category A |
+----+-------+------------+
-- Aggregation with NULL join results
SELECT
COALESCE(l.cat_name, 'Uncategorized') as category,
COUNT(*) as item_count,
COUNT(l.category) as matched_count,
COUNT(*) - COUNT(l.category) as unmatched_count
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
GROUP BY l.cat_name
ORDER BY item_count DESC, category DESC;
+---------------+------------+---------------+-----------------+
| category | item_count | matched_count | unmatched_count |
+---------------+------------+---------------+-----------------+
| Uncategorized | 2 | 0 | 2 |
| Category A | 2 | 2 | 0 |
| Category C | 1 | 1 | 0 |
| Category B | 1 | 1 | 0 |
+---------------+------------+---------------+-----------------+
DROP TABLE table_with_nulls;
Affected Rows: 0
DROP TABLE lookup_table;
Affected Rows: 0

View File

@@ -0,0 +1,58 @@
-- Migrated from DuckDB test: test/sql/join/ NULL handling tests
-- Tests join behavior with NULL values
CREATE TABLE table_with_nulls("id" INTEGER, "value" VARCHAR, category INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE lookup_table(category INTEGER, cat_name VARCHAR, priority INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO table_with_nulls VALUES
(1, 'item1', 1, 1000), (2, 'item2', NULL, 2000), (3, 'item3', 2, 3000),
(4, 'item4', NULL, 4000), (5, 'item5', 3, 5000), (6, 'item6', 1, 6000);
INSERT INTO lookup_table VALUES
(1, 'Category A', 1, 1000), (2, 'Category B', 2, 2000), (3, 'Category C', 3, 3000), (NULL, 'Unknown', 0, 4000);
-- Inner join with NULLs (NULLs won't match)
SELECT t."id", t."value", l.cat_name
FROM table_with_nulls t
INNER JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
-- Left join with NULLs
SELECT t."id", t."value", t.category, COALESCE(l.cat_name, 'No Category') as category_name
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
-- Join with explicit NULL handling
SELECT
t."id", t."value",
CASE
WHEN t.category IS NULL THEN 'NULL Category'
WHEN l.cat_name IS NULL THEN 'Missing Lookup'
ELSE l.cat_name
END as resolved_category
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
ORDER BY t."id";
-- NULL-safe join using COALESCE
SELECT t."id", t."value", l.cat_name
FROM table_with_nulls t
INNER JOIN lookup_table l ON COALESCE(t.category, -1) = COALESCE(l.category, -1)
ORDER BY t."id";
-- Aggregation with NULL join results
SELECT
COALESCE(l.cat_name, 'Uncategorized') as category,
COUNT(*) as item_count,
COUNT(l.category) as matched_count,
COUNT(*) - COUNT(l.category) as unmatched_count
FROM table_with_nulls t
LEFT JOIN lookup_table l ON t.category = l.category
GROUP BY l.cat_name
ORDER BY item_count DESC, category DESC;
DROP TABLE table_with_nulls;
DROP TABLE lookup_table;

View File

@@ -0,0 +1,46 @@
-- Tests join result ordering and deterministic behavior
CREATE TABLE left_data("id" INTEGER, left_val VARCHAR, sort_key INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE right_data("id" INTEGER, right_val VARCHAR, sort_key INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO left_data VALUES (1, 'A1', 10, 1000), (2, 'A2', 5, 2000), (3, 'A3', 15, 3000);
Affected Rows: 3
INSERT INTO right_data VALUES (1, 'B1', 20, 1000), (2, 'B2', 8, 2000), (4, 'B4', 12, 3000);
Affected Rows: 3
SELECT l."id", l.left_val, r.right_val, l.sort_key + r.sort_key as combined_sort
FROM left_data l INNER JOIN right_data r ON l."id" = r."id" ORDER BY l."id";
+----+----------+-----------+---------------+
| id | left_val | right_val | combined_sort |
+----+----------+-----------+---------------+
| 1 | A1 | B1 | 30 |
| 2 | A2 | B2 | 13 |
+----+----------+-----------+---------------+
SELECT l.left_val, r.right_val FROM left_data l FULL OUTER JOIN right_data r ON l."id" = r."id" ORDER BY l."id", r."id";
+----------+-----------+
| left_val | right_val |
+----------+-----------+
| A1 | B1 |
| A2 | B2 |
| A3 | |
| | B4 |
+----------+-----------+
DROP TABLE left_data;
Affected Rows: 0
DROP TABLE right_data;
Affected Rows: 0

View File

@@ -0,0 +1,18 @@
-- Tests join result ordering and deterministic behavior
CREATE TABLE left_data("id" INTEGER, left_val VARCHAR, sort_key INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE right_data("id" INTEGER, right_val VARCHAR, sort_key INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO left_data VALUES (1, 'A1', 10, 1000), (2, 'A2', 5, 2000), (3, 'A3', 15, 3000);
INSERT INTO right_data VALUES (1, 'B1', 20, 1000), (2, 'B2', 8, 2000), (4, 'B4', 12, 3000);
SELECT l."id", l.left_val, r.right_val, l.sort_key + r.sort_key as combined_sort
FROM left_data l INNER JOIN right_data r ON l."id" = r."id" ORDER BY l."id";
SELECT l.left_val, r.right_val FROM left_data l FULL OUTER JOIN right_data r ON l."id" = r."id" ORDER BY l."id", r."id";
DROP TABLE left_data;
DROP TABLE right_data;

View File

@@ -0,0 +1,121 @@
-- Migrated from DuckDB test: test/sql/join/ performance pattern tests
-- Tests join patterns common in time-series queries
CREATE TABLE metrics_perf(metric_id INTEGER, metric_name VARCHAR, "value" DOUBLE, timestamp_val BIGINT, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE metadata_perf(metric_id INTEGER, unit VARCHAR, description VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE thresholds_perf(metric_id INTEGER, warning_level DOUBLE, critical_level DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO metrics_perf VALUES
(1, 'cpu_usage', 65.2, 1700000000, 1000), (1, 'cpu_usage', 72.1, 1700000060, 2000),
(2, 'memory_usage', 85.5, 1700000000, 3000), (2, 'memory_usage', 78.3, 1700000060, 4000),
(3, 'disk_io', 120.7, 1700000000, 5000), (3, 'disk_io', 95.2, 1700000060, 6000);
Affected Rows: 6
INSERT INTO metadata_perf VALUES
(1, 'percent', 'CPU utilization percentage', 1000),
(2, 'percent', 'Memory utilization percentage', 2000),
(3, 'MB/s', 'Disk I/O throughput', 3000);
Affected Rows: 3
INSERT INTO thresholds_perf VALUES
(1, 70.0, 90.0, 1000), (2, 80.0, 95.0, 2000), (3, 100.0, 150.0, 3000);
Affected Rows: 3
-- Join for monitoring dashboard
SELECT
m.metric_name,
md.unit,
m."value",
t.warning_level,
t.critical_level,
CASE
WHEN m."value" >= t.critical_level THEN 'CRITICAL'
WHEN m."value" >= t.warning_level THEN 'WARNING'
ELSE 'OK'
END as status
FROM metrics_perf m
INNER JOIN metadata_perf md ON m.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON m.metric_id = t.metric_id
ORDER BY m.timestamp_val, m.metric_id;
+--------------+---------+-------+---------------+----------------+---------+
| metric_name | unit | value | warning_level | critical_level | status |
+--------------+---------+-------+---------------+----------------+---------+
| cpu_usage | percent | 65.2 | 70.0 | 90.0 | OK |
| memory_usage | percent | 85.5 | 80.0 | 95.0 | WARNING |
| disk_io | MB/s | 120.7 | 100.0 | 150.0 | WARNING |
| cpu_usage | percent | 72.1 | 70.0 | 90.0 | WARNING |
| memory_usage | percent | 78.3 | 80.0 | 95.0 | OK |
| disk_io | MB/s | 95.2 | 100.0 | 150.0 | OK |
+--------------+---------+-------+---------------+----------------+---------+
-- Time-series join with latest values
SELECT
latest_metrics.metric_name,
latest_metrics.latest_value,
md.unit,
t.warning_level
FROM (
SELECT
metric_id,
metric_name,
"value" as latest_value,
ROW_NUMBER() OVER (PARTITION BY metric_id ORDER BY timestamp_val DESC) as rn
FROM metrics_perf
) latest_metrics
INNER JOIN metadata_perf md ON latest_metrics.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON latest_metrics.metric_id = t.metric_id
WHERE latest_metrics.rn = 1
ORDER BY latest_metrics.metric_id;
+--------------+--------------+---------+---------------+
| metric_name | latest_value | unit | warning_level |
+--------------+--------------+---------+---------------+
| cpu_usage | 72.1 | percent | 70.0 |
| memory_usage | 78.3 | percent | 80.0 |
| disk_io | 95.2 | MB/s | 100.0 |
+--------------+--------------+---------+---------------+
-- Historical analysis join
SELECT
md.description,
COUNT(*) as total_readings,
AVG(m."value") as avg_value,
COUNT(CASE WHEN m."value" > t.warning_level THEN 1 END) as warning_count,
COUNT(CASE WHEN m."value" > t.critical_level THEN 1 END) as critical_count
FROM metrics_perf m
INNER JOIN metadata_perf md ON m.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON m.metric_id = t.metric_id
GROUP BY md.description, m.metric_id
ORDER BY critical_count DESC, warning_count DESC, avg_value DESC;
+-------------------------------+----------------+-----------+---------------+----------------+
| description | total_readings | avg_value | warning_count | critical_count |
+-------------------------------+----------------+-----------+---------------+----------------+
| Disk I/O throughput | 2 | 107.95 | 1 | 0 |
| Memory utilization percentage | 2 | 81.9 | 1 | 0 |
| CPU utilization percentage | 2 | 68.65 | 1 | 0 |
+-------------------------------+----------------+-----------+---------------+----------------+
DROP TABLE metrics_perf;
Affected Rows: 0
DROP TABLE metadata_perf;
Affected Rows: 0
DROP TABLE thresholds_perf;
Affected Rows: 0

View File

@@ -0,0 +1,76 @@
-- Migrated from DuckDB test: test/sql/join/ performance pattern tests
-- Tests join patterns common in time-series queries
CREATE TABLE metrics_perf(metric_id INTEGER, metric_name VARCHAR, "value" DOUBLE, timestamp_val BIGINT, ts TIMESTAMP TIME INDEX);
CREATE TABLE metadata_perf(metric_id INTEGER, unit VARCHAR, description VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE thresholds_perf(metric_id INTEGER, warning_level DOUBLE, critical_level DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO metrics_perf VALUES
(1, 'cpu_usage', 65.2, 1700000000, 1000), (1, 'cpu_usage', 72.1, 1700000060, 2000),
(2, 'memory_usage', 85.5, 1700000000, 3000), (2, 'memory_usage', 78.3, 1700000060, 4000),
(3, 'disk_io', 120.7, 1700000000, 5000), (3, 'disk_io', 95.2, 1700000060, 6000);
INSERT INTO metadata_perf VALUES
(1, 'percent', 'CPU utilization percentage', 1000),
(2, 'percent', 'Memory utilization percentage', 2000),
(3, 'MB/s', 'Disk I/O throughput', 3000);
INSERT INTO thresholds_perf VALUES
(1, 70.0, 90.0, 1000), (2, 80.0, 95.0, 2000), (3, 100.0, 150.0, 3000);
-- Join for monitoring dashboard
SELECT
m.metric_name,
md.unit,
m."value",
t.warning_level,
t.critical_level,
CASE
WHEN m."value" >= t.critical_level THEN 'CRITICAL'
WHEN m."value" >= t.warning_level THEN 'WARNING'
ELSE 'OK'
END as status
FROM metrics_perf m
INNER JOIN metadata_perf md ON m.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON m.metric_id = t.metric_id
ORDER BY m.timestamp_val, m.metric_id;
-- Time-series join with latest values
SELECT
latest_metrics.metric_name,
latest_metrics.latest_value,
md.unit,
t.warning_level
FROM (
SELECT
metric_id,
metric_name,
"value" as latest_value,
ROW_NUMBER() OVER (PARTITION BY metric_id ORDER BY timestamp_val DESC) as rn
FROM metrics_perf
) latest_metrics
INNER JOIN metadata_perf md ON latest_metrics.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON latest_metrics.metric_id = t.metric_id
WHERE latest_metrics.rn = 1
ORDER BY latest_metrics.metric_id;
-- Historical analysis join
SELECT
md.description,
COUNT(*) as total_readings,
AVG(m."value") as avg_value,
COUNT(CASE WHEN m."value" > t.warning_level THEN 1 END) as warning_count,
COUNT(CASE WHEN m."value" > t.critical_level THEN 1 END) as critical_count
FROM metrics_perf m
INNER JOIN metadata_perf md ON m.metric_id = md.metric_id
INNER JOIN thresholds_perf t ON m.metric_id = t.metric_id
GROUP BY md.description, m.metric_id
ORDER BY critical_count DESC, warning_count DESC, avg_value DESC;
DROP TABLE metrics_perf;
DROP TABLE metadata_perf;
DROP TABLE thresholds_perf;

View File

@@ -0,0 +1,44 @@
-- Tests join predicate pushdown optimization scenarios
CREATE TABLE events_push(event_id INTEGER, user_id INTEGER, event_type VARCHAR, "value" INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE users_push(user_id INTEGER, user_name VARCHAR, region VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO events_push VALUES (1, 100, 'click', 1, 1000), (2, 100, 'view', 2, 2000), (3, 200, 'click', 1, 3000), (4, 300, 'purchase', 5, 4000);
Affected Rows: 4
INSERT INTO users_push VALUES (100, 'Alice', 'US', 1000), (200, 'Bob', 'EU', 2000), (300, 'Charlie', 'US', 3000);
Affected Rows: 3
SELECT e.event_type, u.region, COUNT(*) as event_count FROM events_push e INNER JOIN users_push u ON e.user_id = u.user_id WHERE u.region = 'US' GROUP BY e.event_type, u.region ORDER BY event_count DESC, e.event_type ASC;
+------------+--------+-------------+
| event_type | region | event_count |
+------------+--------+-------------+
| click | US | 1 |
| purchase | US | 1 |
| view | US | 1 |
+------------+--------+-------------+
SELECT u.user_name, SUM(e."value") as total_value FROM users_push u INNER JOIN events_push e ON u.user_id = e.user_id WHERE e.event_type = 'click' GROUP BY u.user_id, u.user_name ORDER BY total_value DESC, u.user_name ASC;
+-----------+-------------+
| user_name | total_value |
+-----------+-------------+
| Alice | 1 |
| Bob | 1 |
+-----------+-------------+
DROP TABLE events_push;
Affected Rows: 0
DROP TABLE users_push;
Affected Rows: 0

View File

@@ -0,0 +1,17 @@
-- Tests join predicate pushdown optimization scenarios
CREATE TABLE events_push(event_id INTEGER, user_id INTEGER, event_type VARCHAR, "value" INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE users_push(user_id INTEGER, user_name VARCHAR, region VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO events_push VALUES (1, 100, 'click', 1, 1000), (2, 100, 'view', 2, 2000), (3, 200, 'click', 1, 3000), (4, 300, 'purchase', 5, 4000);
INSERT INTO users_push VALUES (100, 'Alice', 'US', 1000), (200, 'Bob', 'EU', 2000), (300, 'Charlie', 'US', 3000);
SELECT e.event_type, u.region, COUNT(*) as event_count FROM events_push e INNER JOIN users_push u ON e.user_id = u.user_id WHERE u.region = 'US' GROUP BY e.event_type, u.region ORDER BY event_count DESC, e.event_type ASC;
SELECT u.user_name, SUM(e."value") as total_value FROM users_push u INNER JOIN events_push e ON u.user_id = e.user_id WHERE e.event_type = 'click' GROUP BY u.user_id, u.user_name ORDER BY total_value DESC, u.user_name ASC;
DROP TABLE events_push;
DROP TABLE users_push;

View File

@@ -0,0 +1,38 @@
-- Tests self-join patterns
CREATE TABLE employee_hierarchy(emp_id INTEGER, emp_name VARCHAR, manager_id INTEGER, level_num INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO employee_hierarchy VALUES
(1, 'CEO', NULL, 1, 1000), (2, 'CTO', 1, 2, 2000), (3, 'Dev1', 2, 3, 3000), (4, 'Dev2', 2, 3, 4000), (5, 'QA1', 2, 3, 5000);
Affected Rows: 5
SELECT e.emp_name as employee, m.emp_name as manager FROM employee_hierarchy e LEFT JOIN employee_hierarchy m ON e.manager_id = m.emp_id ORDER BY e.level_num, e.emp_id;
+----------+---------+
| employee | manager |
+----------+---------+
| CEO | |
| CTO | CEO |
| Dev1 | CTO |
| Dev2 | CTO |
| QA1 | CTO |
+----------+---------+
SELECT m.emp_name as manager, COUNT(e.emp_id) as direct_reports FROM employee_hierarchy m LEFT JOIN employee_hierarchy e ON m.emp_id = e.manager_id GROUP BY m.emp_id, m.emp_name ORDER BY direct_reports DESC, manager DESC;
+---------+----------------+
| manager | direct_reports |
+---------+----------------+
| CTO | 3 |
| CEO | 1 |
| QA1 | 0 |
| Dev2 | 0 |
| Dev1 | 0 |
+---------+----------------+
DROP TABLE employee_hierarchy;
Affected Rows: 0

View File

@@ -0,0 +1,11 @@
-- Tests self-join patterns
CREATE TABLE employee_hierarchy(emp_id INTEGER, emp_name VARCHAR, manager_id INTEGER, level_num INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO employee_hierarchy VALUES
(1, 'CEO', NULL, 1, 1000), (2, 'CTO', 1, 2, 2000), (3, 'Dev1', 2, 3, 3000), (4, 'Dev2', 2, 3, 4000), (5, 'QA1', 2, 3, 5000);
SELECT e.emp_name as employee, m.emp_name as manager FROM employee_hierarchy e LEFT JOIN employee_hierarchy m ON e.manager_id = m.emp_id ORDER BY e.level_num, e.emp_id;
SELECT m.emp_name as manager, COUNT(e.emp_id) as direct_reports FROM employee_hierarchy m LEFT JOIN employee_hierarchy e ON m.emp_id = e.manager_id GROUP BY m.emp_id, m.emp_name ORDER BY direct_reports DESC, manager DESC;
DROP TABLE employee_hierarchy;

View File

@@ -0,0 +1,83 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_join_types.test
-- Tests different join types and conditions
CREATE TABLE customers("id" INTEGER, "name" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE orders(order_id INTEGER, customer_id INTEGER, amount INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO customers VALUES (1, 'Alice', 1000), (2, 'Bob', 2000), (3, 'Carol', 3000);
Affected Rows: 3
INSERT INTO orders VALUES (101, 1, 100, 4000), (102, 1, 200, 5000), (103, 2, 150, 6000), (104, 4, 300, 7000);
Affected Rows: 4
-- INNER JOIN
SELECT c."name", o.amount FROM customers c INNER JOIN orders o ON c."id" = o.customer_id ORDER BY c."name", o.amount;
+-------+--------+
| name | amount |
+-------+--------+
| Alice | 100 |
| Alice | 200 |
| Bob | 150 |
+-------+--------+
-- LEFT JOIN showing unmatched customers
SELECT c."name", o.amount FROM customers c LEFT JOIN orders o ON c."id" = o.customer_id ORDER BY c."name", o.amount NULLS LAST;
+-------+--------+
| name | amount |
+-------+--------+
| Alice | 100 |
| Alice | 200 |
| Bob | 150 |
| Carol | |
+-------+--------+
-- RIGHT JOIN showing unmatched orders
SELECT c."name", o.amount FROM customers c RIGHT JOIN orders o ON c."id" = o.customer_id ORDER BY c."name" NULLS LAST, o.amount;
+-------+--------+
| name | amount |
+-------+--------+
| Alice | 100 |
| Alice | 200 |
| Bob | 150 |
| | 300 |
+-------+--------+
-- FULL OUTER JOIN showing all unmatched
SELECT c."name", o.amount FROM customers c FULL OUTER JOIN orders o ON c."id" = o.customer_id ORDER BY c."name" NULLS LAST, o.amount NULLS LAST;
+-------+--------+
| name | amount |
+-------+--------+
| Alice | 100 |
| Alice | 200 |
| Bob | 150 |
| Carol | |
| | 300 |
+-------+--------+
-- JOIN with additional conditions
SELECT c."name", o.amount FROM customers c JOIN orders o ON c."id" = o.customer_id AND o.amount > 150 ORDER BY c."name";
+-------+--------+
| name | amount |
+-------+--------+
| Alice | 200 |
+-------+--------+
DROP TABLE orders;
Affected Rows: 0
DROP TABLE customers;
Affected Rows: 0

View File

@@ -0,0 +1,29 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_join_types.test
-- Tests different join types and conditions
CREATE TABLE customers("id" INTEGER, "name" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE orders(order_id INTEGER, customer_id INTEGER, amount INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO customers VALUES (1, 'Alice', 1000), (2, 'Bob', 2000), (3, 'Carol', 3000);
INSERT INTO orders VALUES (101, 1, 100, 4000), (102, 1, 200, 5000), (103, 2, 150, 6000), (104, 4, 300, 7000);
-- INNER JOIN
SELECT c."name", o.amount FROM customers c INNER JOIN orders o ON c."id" = o.customer_id ORDER BY c."name", o.amount;
-- LEFT JOIN showing unmatched customers
SELECT c."name", o.amount FROM customers c LEFT JOIN orders o ON c."id" = o.customer_id ORDER BY c."name", o.amount NULLS LAST;
-- RIGHT JOIN showing unmatched orders
SELECT c."name", o.amount FROM customers c RIGHT JOIN orders o ON c."id" = o.customer_id ORDER BY c."name" NULLS LAST, o.amount;
-- FULL OUTER JOIN showing all unmatched
SELECT c."name", o.amount FROM customers c FULL OUTER JOIN orders o ON c."id" = o.customer_id ORDER BY c."name" NULLS LAST, o.amount NULLS LAST;
-- JOIN with additional conditions
SELECT c."name", o.amount FROM customers c JOIN orders o ON c."id" = o.customer_id AND o.amount > 150 ORDER BY c."name";
DROP TABLE orders;
DROP TABLE customers;

View File

@@ -0,0 +1,37 @@
-- Tests joins combined with window functions
CREATE TABLE sales_data_win(rep_id INTEGER, sale_amount DOUBLE, sale_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE rep_targets(rep_id INTEGER, quarterly_target DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO sales_data_win VALUES (1, 1000, '2023-01-01', 1000), (1, 1500, '2023-01-15', 2000), (2, 800, '2023-01-02', 3000), (2, 1200, '2023-01-16', 4000), (3, 2000, '2023-01-03', 5000);
Affected Rows: 5
INSERT INTO rep_targets VALUES (1, 5000, 1000), (2, 4000, 2000), (3, 6000, 3000);
Affected Rows: 3
SELECT s.rep_id, s.sale_amount, rt.quarterly_target, SUM(s.sale_amount) OVER (PARTITION BY s.rep_id ORDER BY s.sale_date) as running_total FROM sales_data_win s INNER JOIN rep_targets rt ON s.rep_id = rt.rep_id ORDER BY s.rep_id, s.sale_date;
+--------+-------------+------------------+---------------+
| rep_id | sale_amount | quarterly_target | running_total |
+--------+-------------+------------------+---------------+
| 1 | 1000.0 | 5000.0 | 1000.0 |
| 1 | 1500.0 | 5000.0 | 2500.0 |
| 2 | 800.0 | 4000.0 | 800.0 |
| 2 | 1200.0 | 4000.0 | 2000.0 |
| 3 | 2000.0 | 6000.0 | 2000.0 |
+--------+-------------+------------------+---------------+
DROP TABLE sales_data_win;
Affected Rows: 0
DROP TABLE rep_targets;
Affected Rows: 0

View File

@@ -0,0 +1,15 @@
-- Tests joins combined with window functions
CREATE TABLE sales_data_win(rep_id INTEGER, sale_amount DOUBLE, sale_date DATE, ts TIMESTAMP TIME INDEX);
CREATE TABLE rep_targets(rep_id INTEGER, quarterly_target DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO sales_data_win VALUES (1, 1000, '2023-01-01', 1000), (1, 1500, '2023-01-15', 2000), (2, 800, '2023-01-02', 3000), (2, 1200, '2023-01-16', 4000), (3, 2000, '2023-01-03', 5000);
INSERT INTO rep_targets VALUES (1, 5000, 1000), (2, 4000, 2000), (3, 6000, 3000);
SELECT s.rep_id, s.sale_amount, rt.quarterly_target, SUM(s.sale_amount) OVER (PARTITION BY s.rep_id ORDER BY s.sale_date) as running_total FROM sales_data_win s INNER JOIN rep_targets rt ON s.rep_id = rt.rep_id ORDER BY s.rep_id, s.sale_date;
DROP TABLE sales_data_win;
DROP TABLE rep_targets;

View File

@@ -0,0 +1,146 @@
-- Migrated from DuckDB test: test/sql/join/ join with aggregate tests
-- Tests joins combined with aggregate functions
CREATE TABLE sensors(sensor_id INTEGER, sensor_name VARCHAR, "location" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE readings(reading_id INTEGER, sensor_id INTEGER, "value" DOUBLE, reading_time TIMESTAMP, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO sensors VALUES
(1, 'TempSensor1', 'Room A', 1000), (2, 'TempSensor2', 'Room B', 2000),
(3, 'HumiditySensor1', 'Room A', 3000), (4, 'HumiditySensor2', 'Room B', 4000);
Affected Rows: 4
INSERT INTO readings VALUES
(1, 1, 22.5, '2023-01-01 10:00:00', 1000), (2, 1, 23.1, '2023-01-01 11:00:00', 2000),
(3, 1, 21.8, '2023-01-01 12:00:00', 3000), (4, 2, 25.3, '2023-01-01 10:00:00', 4000),
(5, 2, 26.0, '2023-01-01 11:00:00', 5000), (6, 2, 24.7, '2023-01-01 12:00:00', 6000),
(7, 3, 45.2, '2023-01-01 10:00:00', 7000), (8, 3, 46.8, '2023-01-01 11:00:00', 8000),
(9, 4, 52.1, '2023-01-01 10:00:00', 9000), (10, 4, 51.3, '2023-01-01 11:00:00', 10000);
Affected Rows: 10
-- Join with basic aggregation
SELECT
s.sensor_name, s."location",
COUNT(r.reading_id) as reading_count,
AVG(r."value") as avg_value,
MIN(r."value") as min_value,
MAX(r."value") as max_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s.sensor_id, s.sensor_name, s."location"
ORDER BY s.sensor_name;
+-----------------+----------+---------------+--------------------+-----------+-----------+
| sensor_name | location | reading_count | avg_value | min_value | max_value |
+-----------------+----------+---------------+--------------------+-----------+-----------+
| HumiditySensor1 | Room A | 2 | 46.0 | 45.2 | 46.8 |
| HumiditySensor2 | Room B | 2 | 51.7 | 51.3 | 52.1 |
| TempSensor1 | Room A | 3 | 22.46666666666667 | 21.8 | 23.1 |
| TempSensor2 | Room B | 3 | 25.333333333333332 | 24.7 | 26.0 |
+-----------------+----------+---------------+--------------------+-----------+-----------+
-- Join with time-based aggregation
SELECT
s."location",
DATE_TRUNC('hour', r.reading_time) as hour_bucket,
COUNT(*) as readings_per_hour,
AVG(r."value") as avg_hourly_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s."location", DATE_TRUNC('hour', r.reading_time)
ORDER BY s."location", hour_bucket;
+----------+---------------------+-------------------+------------------+
| location | hour_bucket | readings_per_hour | avg_hourly_value |
+----------+---------------------+-------------------+------------------+
| Room A | 2023-01-01T10:00:00 | 2 | 33.85 |
| Room A | 2023-01-01T11:00:00 | 2 | 34.95 |
| Room A | 2023-01-01T12:00:00 | 1 | 21.8 |
| Room B | 2023-01-01T10:00:00 | 2 | 38.7 |
| Room B | 2023-01-01T11:00:00 | 2 | 38.65 |
| Room B | 2023-01-01T12:00:00 | 1 | 24.7 |
+----------+---------------------+-------------------+------------------+
-- Aggregation before join
SELECT
s.sensor_name, s."location", agg_readings.avg_value, agg_readings.reading_count
FROM sensors s
INNER JOIN (
SELECT sensor_id, AVG("value") as avg_value, COUNT(*) as reading_count
FROM readings
GROUP BY sensor_id
) agg_readings ON s.sensor_id = agg_readings.sensor_id
WHERE agg_readings.avg_value > 30.0
ORDER BY agg_readings.avg_value DESC;
+-----------------+----------+-----------+---------------+
| sensor_name | location | avg_value | reading_count |
+-----------------+----------+-----------+---------------+
| HumiditySensor2 | Room B | 51.7 | 2 |
| HumiditySensor1 | Room A | 46.0 | 2 |
+-----------------+----------+-----------+---------------+
-- Multiple aggregation levels with joins
SELECT
location_summary.location,
location_summary.sensor_count,
location_summary.avg_readings_per_sensor,
location_summary.location_avg_value
FROM (
SELECT
s."location",
COUNT(DISTINCT s.sensor_id) as sensor_count,
COUNT(r.reading_id) / COUNT(DISTINCT s.sensor_id) as avg_readings_per_sensor,
AVG(r."value") as location_avg_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s."location"
) location_summary
ORDER BY location_summary.location_avg_value DESC;
+----------+--------------+-------------------------+--------------------+
| location | sensor_count | avg_readings_per_sensor | location_avg_value |
+----------+--------------+-------------------------+--------------------+
| Room B | 2 | 2 | 35.88 |
| Room A | 2 | 2 | 31.880000000000003 |
+----------+--------------+-------------------------+--------------------+
-- Join with aggregated conditions
SELECT
s.sensor_name,
high_readings.high_count,
high_readings.avg_high_value
FROM sensors s
INNER JOIN (
SELECT
sensor_id,
COUNT(*) as high_count,
AVG("value") as avg_high_value
FROM readings
WHERE "value" > 25.0
GROUP BY sensor_id
HAVING COUNT(*) >= 2
) high_readings ON s.sensor_id = high_readings.sensor_id
ORDER BY high_readings.avg_high_value DESC;
+-----------------+------------+----------------+
| sensor_name | high_count | avg_high_value |
+-----------------+------------+----------------+
| HumiditySensor2 | 2 | 51.7 |
| HumiditySensor1 | 2 | 46.0 |
| TempSensor2 | 2 | 25.65 |
+-----------------+------------+----------------+
DROP TABLE sensors;
Affected Rows: 0
DROP TABLE readings;
Affected Rows: 0

View File

@@ -0,0 +1,92 @@
-- Migrated from DuckDB test: test/sql/join/ join with aggregate tests
-- Tests joins combined with aggregate functions
CREATE TABLE sensors(sensor_id INTEGER, sensor_name VARCHAR, "location" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE readings(reading_id INTEGER, sensor_id INTEGER, "value" DOUBLE, reading_time TIMESTAMP, ts TIMESTAMP TIME INDEX);
INSERT INTO sensors VALUES
(1, 'TempSensor1', 'Room A', 1000), (2, 'TempSensor2', 'Room B', 2000),
(3, 'HumiditySensor1', 'Room A', 3000), (4, 'HumiditySensor2', 'Room B', 4000);
INSERT INTO readings VALUES
(1, 1, 22.5, '2023-01-01 10:00:00', 1000), (2, 1, 23.1, '2023-01-01 11:00:00', 2000),
(3, 1, 21.8, '2023-01-01 12:00:00', 3000), (4, 2, 25.3, '2023-01-01 10:00:00', 4000),
(5, 2, 26.0, '2023-01-01 11:00:00', 5000), (6, 2, 24.7, '2023-01-01 12:00:00', 6000),
(7, 3, 45.2, '2023-01-01 10:00:00', 7000), (8, 3, 46.8, '2023-01-01 11:00:00', 8000),
(9, 4, 52.1, '2023-01-01 10:00:00', 9000), (10, 4, 51.3, '2023-01-01 11:00:00', 10000);
-- Join with basic aggregation
SELECT
s.sensor_name, s."location",
COUNT(r.reading_id) as reading_count,
AVG(r."value") as avg_value,
MIN(r."value") as min_value,
MAX(r."value") as max_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s.sensor_id, s.sensor_name, s."location"
ORDER BY s.sensor_name;
-- Join with time-based aggregation
SELECT
s."location",
DATE_TRUNC('hour', r.reading_time) as hour_bucket,
COUNT(*) as readings_per_hour,
AVG(r."value") as avg_hourly_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s."location", DATE_TRUNC('hour', r.reading_time)
ORDER BY s."location", hour_bucket;
-- Aggregation before join
SELECT
s.sensor_name, s."location", agg_readings.avg_value, agg_readings.reading_count
FROM sensors s
INNER JOIN (
SELECT sensor_id, AVG("value") as avg_value, COUNT(*) as reading_count
FROM readings
GROUP BY sensor_id
) agg_readings ON s.sensor_id = agg_readings.sensor_id
WHERE agg_readings.avg_value > 30.0
ORDER BY agg_readings.avg_value DESC;
-- Multiple aggregation levels with joins
SELECT
location_summary.location,
location_summary.sensor_count,
location_summary.avg_readings_per_sensor,
location_summary.location_avg_value
FROM (
SELECT
s."location",
COUNT(DISTINCT s.sensor_id) as sensor_count,
COUNT(r.reading_id) / COUNT(DISTINCT s.sensor_id) as avg_readings_per_sensor,
AVG(r."value") as location_avg_value
FROM sensors s
INNER JOIN readings r ON s.sensor_id = r.sensor_id
GROUP BY s."location"
) location_summary
ORDER BY location_summary.location_avg_value DESC;
-- Join with aggregated conditions
SELECT
s.sensor_name,
high_readings.high_count,
high_readings.avg_high_value
FROM sensors s
INNER JOIN (
SELECT
sensor_id,
COUNT(*) as high_count,
AVG("value") as avg_high_value
FROM readings
WHERE "value" > 25.0
GROUP BY sensor_id
HAVING COUNT(*) >= 2
) high_readings ON s.sensor_id = high_readings.sensor_id
ORDER BY high_readings.avg_high_value DESC;
DROP TABLE sensors;
DROP TABLE readings;

View File

@@ -0,0 +1,147 @@
-- Migrated from DuckDB test: test/sql/join/ expression join tests
-- Tests joins with complex expressions
CREATE TABLE measurements(measure_id INTEGER, sensor_id INTEGER, reading DOUBLE, measure_time TIMESTAMP, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE sensor_config(sensor_id INTEGER, min_threshold DOUBLE, max_threshold DOUBLE, calibration_factor DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO measurements VALUES
(1, 1, 22.5, '2023-01-01 10:00:00', 1000), (2, 1, 45.8, '2023-01-01 10:05:00', 2000),
(3, 2, 18.2, '2023-01-01 10:00:00', 3000), (4, 2, 89.7, '2023-01-01 10:05:00', 4000),
(5, 3, 35.1, '2023-01-01 10:00:00', 5000), (6, 3, 42.3, '2023-01-01 10:05:00', 6000);
Affected Rows: 6
INSERT INTO sensor_config VALUES
(1, 20.0, 50.0, 1.05, 1000), (2, 15.0, 85.0, 0.98, 2000), (3, 30.0, 70.0, 1.02, 3000);
Affected Rows: 3
-- Join with mathematical expressions
SELECT
m.measure_id,
m.reading,
m.reading * sc.calibration_factor as calibrated_reading,
sc.min_threshold,
sc.max_threshold
FROM measurements m
INNER JOIN sensor_config sc ON m.sensor_id = sc.sensor_id
ORDER BY m.measure_id;
+------------+---------+--------------------+---------------+---------------+
| measure_id | reading | calibrated_reading | min_threshold | max_threshold |
+------------+---------+--------------------+---------------+---------------+
| 1 | 22.5 | 23.625 | 20.0 | 50.0 |
| 2 | 45.8 | 48.089999999999996 | 20.0 | 50.0 |
| 3 | 18.2 | 17.836 | 15.0 | 85.0 |
| 4 | 89.7 | 87.906 | 15.0 | 85.0 |
| 5 | 35.1 | 35.802 | 30.0 | 70.0 |
| 6 | 42.3 | 43.146 | 30.0 | 70.0 |
+------------+---------+--------------------+---------------+---------------+
-- Join with conditional expressions
SELECT
m.measure_id,
m.reading,
sc.calibration_factor,
CASE
WHEN m.reading * sc.calibration_factor < sc.min_threshold THEN 'Below Range'
WHEN m.reading * sc.calibration_factor > sc.max_threshold THEN 'Above Range'
ELSE 'In Range'
END as reading_status
FROM measurements m
INNER JOIN sensor_config sc
ON m.sensor_id = sc.sensor_id
AND m.reading BETWEEN sc.min_threshold * 0.5 AND sc.max_threshold * 1.5
ORDER BY m.measure_id;
+------------+---------+--------------------+----------------+
| measure_id | reading | calibration_factor | reading_status |
+------------+---------+--------------------+----------------+
| 1 | 22.5 | 1.05 | In Range |
| 2 | 45.8 | 1.05 | In Range |
| 3 | 18.2 | 0.98 | In Range |
| 4 | 89.7 | 0.98 | Above Range |
| 5 | 35.1 | 1.02 | In Range |
| 6 | 42.3 | 1.02 | In Range |
+------------+---------+--------------------+----------------+
-- Join with aggregated expressions
SELECT
sc.sensor_id,
COUNT(*) as total_readings,
AVG(m.reading * sc.calibration_factor) as avg_calibrated,
COUNT(CASE WHEN m.reading * sc.calibration_factor > sc.max_threshold THEN 1 END) as over_threshold_count
FROM measurements m
INNER JOIN sensor_config sc ON m.sensor_id = sc.sensor_id
GROUP BY sc.sensor_id, sc.calibration_factor, sc.max_threshold
HAVING AVG(m.reading * sc.calibration_factor) > 30.0
ORDER BY avg_calibrated DESC;
+-----------+----------------+--------------------+----------------------+
| sensor_id | total_readings | avg_calibrated | over_threshold_count |
+-----------+----------------+--------------------+----------------------+
| 2 | 2 | 52.871 | 1 |
| 3 | 2 | 39.474000000000004 | 0 |
| 1 | 2 | 35.8575 | 0 |
+-----------+----------------+--------------------+----------------------+
-- Join with string expression conditions
CREATE TABLE devices(device_id INTEGER, device_code VARCHAR, "status" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE device_logs(log_id INTEGER, device_code VARCHAR, log_message VARCHAR, severity INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO devices VALUES
(1, 'DEV001', 'active', 1000), (2, 'DEV002', 'inactive', 2000), (3, 'DEV003', 'active', 3000);
Affected Rows: 3
INSERT INTO device_logs VALUES
(1, 'DEV001', 'System started', 1, 1000), (2, 'DEV001', 'Warning detected', 2, 2000),
(3, 'DEV002', 'Error occurred', 3, 3000), (4, 'DEV003', 'Normal operation', 1, 4000);
Affected Rows: 4
-- Join with string expression matching
SELECT
d.device_id,
d."status",
dl.log_message,
dl.severity
FROM devices d
INNER JOIN device_logs dl
ON UPPER(d.device_code) = UPPER(dl.device_code)
AND d."status" = 'active'
ORDER BY d.device_id, dl.severity DESC;
+-----------+--------+------------------+----------+
| device_id | status | log_message | severity |
+-----------+--------+------------------+----------+
| 1 | active | Warning detected | 2 |
| 1 | active | System started | 1 |
| 3 | active | Normal operation | 1 |
+-----------+--------+------------------+----------+
DROP TABLE measurements;
Affected Rows: 0
DROP TABLE sensor_config;
Affected Rows: 0
DROP TABLE devices;
Affected Rows: 0
DROP TABLE device_logs;
Affected Rows: 0

View File

@@ -0,0 +1,84 @@
-- Migrated from DuckDB test: test/sql/join/ expression join tests
-- Tests joins with complex expressions
CREATE TABLE measurements(measure_id INTEGER, sensor_id INTEGER, reading DOUBLE, measure_time TIMESTAMP, ts TIMESTAMP TIME INDEX);
CREATE TABLE sensor_config(sensor_id INTEGER, min_threshold DOUBLE, max_threshold DOUBLE, calibration_factor DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO measurements VALUES
(1, 1, 22.5, '2023-01-01 10:00:00', 1000), (2, 1, 45.8, '2023-01-01 10:05:00', 2000),
(3, 2, 18.2, '2023-01-01 10:00:00', 3000), (4, 2, 89.7, '2023-01-01 10:05:00', 4000),
(5, 3, 35.1, '2023-01-01 10:00:00', 5000), (6, 3, 42.3, '2023-01-01 10:05:00', 6000);
INSERT INTO sensor_config VALUES
(1, 20.0, 50.0, 1.05, 1000), (2, 15.0, 85.0, 0.98, 2000), (3, 30.0, 70.0, 1.02, 3000);
-- Join with mathematical expressions
SELECT
m.measure_id,
m.reading,
m.reading * sc.calibration_factor as calibrated_reading,
sc.min_threshold,
sc.max_threshold
FROM measurements m
INNER JOIN sensor_config sc ON m.sensor_id = sc.sensor_id
ORDER BY m.measure_id;
-- Join with conditional expressions
SELECT
m.measure_id,
m.reading,
sc.calibration_factor,
CASE
WHEN m.reading * sc.calibration_factor < sc.min_threshold THEN 'Below Range'
WHEN m.reading * sc.calibration_factor > sc.max_threshold THEN 'Above Range'
ELSE 'In Range'
END as reading_status
FROM measurements m
INNER JOIN sensor_config sc
ON m.sensor_id = sc.sensor_id
AND m.reading BETWEEN sc.min_threshold * 0.5 AND sc.max_threshold * 1.5
ORDER BY m.measure_id;
-- Join with aggregated expressions
SELECT
sc.sensor_id,
COUNT(*) as total_readings,
AVG(m.reading * sc.calibration_factor) as avg_calibrated,
COUNT(CASE WHEN m.reading * sc.calibration_factor > sc.max_threshold THEN 1 END) as over_threshold_count
FROM measurements m
INNER JOIN sensor_config sc ON m.sensor_id = sc.sensor_id
GROUP BY sc.sensor_id, sc.calibration_factor, sc.max_threshold
HAVING AVG(m.reading * sc.calibration_factor) > 30.0
ORDER BY avg_calibrated DESC;
-- Join with string expression conditions
CREATE TABLE devices(device_id INTEGER, device_code VARCHAR, "status" VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE device_logs(log_id INTEGER, device_code VARCHAR, log_message VARCHAR, severity INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO devices VALUES
(1, 'DEV001', 'active', 1000), (2, 'DEV002', 'inactive', 2000), (3, 'DEV003', 'active', 3000);
INSERT INTO device_logs VALUES
(1, 'DEV001', 'System started', 1, 1000), (2, 'DEV001', 'Warning detected', 2, 2000),
(3, 'DEV002', 'Error occurred', 3, 3000), (4, 'DEV003', 'Normal operation', 1, 4000);
-- Join with string expression matching
SELECT
d.device_id,
d."status",
dl.log_message,
dl.severity
FROM devices d
INNER JOIN device_logs dl
ON UPPER(d.device_code) = UPPER(dl.device_code)
AND d."status" = 'active'
ORDER BY d.device_id, dl.severity DESC;
DROP TABLE measurements;
DROP TABLE sensor_config;
DROP TABLE devices;
DROP TABLE device_logs;

View File

@@ -0,0 +1,76 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_join_with_nulls.test
-- Tests JOIN behavior with NULL values
CREATE TABLE null_left("id" INTEGER, val VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE null_right("id" INTEGER, val VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO null_left VALUES (1, 'A', 1000), (2, NULL, 2000), (NULL, 'C', 3000), (4, 'D', 4000);
Affected Rows: 4
INSERT INTO null_right VALUES (1, 'X', 5000), (NULL, 'Y', 6000), (3, 'Z', 7000), (4, NULL, 8000);
Affected Rows: 4
-- INNER JOIN with NULLs (NULLs don't match)
SELECT * FROM null_left l INNER JOIN null_right r ON l."id" = r."id" ORDER BY l.ts;
+----+-----+---------------------+----+-----+---------------------+
| id | val | ts | id | val | ts |
+----+-----+---------------------+----+-----+---------------------+
| 1 | A | 1970-01-01T00:00:01 | 1 | X | 1970-01-01T00:00:05 |
| 4 | D | 1970-01-01T00:00:04 | 4 | | 1970-01-01T00:00:08 |
+----+-----+---------------------+----+-----+---------------------+
-- LEFT JOIN with NULLs
SELECT * FROM null_left l LEFT JOIN null_right r ON l."id" = r."id" ORDER BY l.ts;
+----+-----+---------------------+----+-----+---------------------+
| id | val | ts | id | val | ts |
+----+-----+---------------------+----+-----+---------------------+
| 1 | A | 1970-01-01T00:00:01 | 1 | X | 1970-01-01T00:00:05 |
| 2 | | 1970-01-01T00:00:02 | | | |
| | C | 1970-01-01T00:00:03 | | | |
| 4 | D | 1970-01-01T00:00:04 | 4 | | 1970-01-01T00:00:08 |
+----+-----+---------------------+----+-----+---------------------+
-- JOIN on string columns with NULLs
SELECT * FROM null_left l INNER JOIN null_right r ON l.val = r.val ORDER BY l.ts;
++
++
-- JOIN with IS NOT DISTINCT FROM (treats NULL=NULL as true)
SELECT * FROM null_left l INNER JOIN null_right r ON l."id" IS NOT DISTINCT FROM r."id" ORDER BY l.ts;
+----+-----+---------------------+----+-----+---------------------+
| id | val | ts | id | val | ts |
+----+-----+---------------------+----+-----+---------------------+
| 1 | A | 1970-01-01T00:00:01 | 1 | X | 1970-01-01T00:00:05 |
| | C | 1970-01-01T00:00:03 | | Y | 1970-01-01T00:00:06 |
| 4 | D | 1970-01-01T00:00:04 | 4 | | 1970-01-01T00:00:08 |
+----+-----+---------------------+----+-----+---------------------+
-- JOIN with NULL-safe conditions
SELECT * FROM null_left l INNER JOIN null_right r ON (l."id" = r."id" OR (l."id" IS NULL AND r."id" IS NULL)) ORDER BY l.ts;
+----+-----+---------------------+----+-----+---------------------+
| id | val | ts | id | val | ts |
+----+-----+---------------------+----+-----+---------------------+
| 1 | A | 1970-01-01T00:00:01 | 1 | X | 1970-01-01T00:00:05 |
| | C | 1970-01-01T00:00:03 | | Y | 1970-01-01T00:00:06 |
| 4 | D | 1970-01-01T00:00:04 | 4 | | 1970-01-01T00:00:08 |
+----+-----+---------------------+----+-----+---------------------+
DROP TABLE null_right;
Affected Rows: 0
DROP TABLE null_left;
Affected Rows: 0

View File

@@ -0,0 +1,29 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_join_with_nulls.test
-- Tests JOIN behavior with NULL values
CREATE TABLE null_left("id" INTEGER, val VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE null_right("id" INTEGER, val VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO null_left VALUES (1, 'A', 1000), (2, NULL, 2000), (NULL, 'C', 3000), (4, 'D', 4000);
INSERT INTO null_right VALUES (1, 'X', 5000), (NULL, 'Y', 6000), (3, 'Z', 7000), (4, NULL, 8000);
-- INNER JOIN with NULLs (NULLs don't match)
SELECT * FROM null_left l INNER JOIN null_right r ON l."id" = r."id" ORDER BY l.ts;
-- LEFT JOIN with NULLs
SELECT * FROM null_left l LEFT JOIN null_right r ON l."id" = r."id" ORDER BY l.ts;
-- JOIN on string columns with NULLs
SELECT * FROM null_left l INNER JOIN null_right r ON l.val = r.val ORDER BY l.ts;
-- JOIN with IS NOT DISTINCT FROM (treats NULL=NULL as true)
SELECT * FROM null_left l INNER JOIN null_right r ON l."id" IS NOT DISTINCT FROM r."id" ORDER BY l.ts;
-- JOIN with NULL-safe conditions
SELECT * FROM null_left l INNER JOIN null_right r ON (l."id" = r."id" OR (l."id" IS NULL AND r."id" IS NULL)) ORDER BY l.ts;
DROP TABLE null_right;
DROP TABLE null_left;

View File

@@ -0,0 +1,155 @@
-- Migrated from DuckDB test: test/sql/join/ subquery join tests
-- Tests joins involving subqueries
CREATE TABLE products_sub(prod_id INTEGER, prod_name VARCHAR, category_id INTEGER, price DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE categories_sub(cat_id INTEGER, cat_name VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE sales_sub(sale_id INTEGER, prod_id INTEGER, quantity INTEGER, sale_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO products_sub VALUES
(1, 'Laptop', 1, 1200.00, 1000), (2, 'Mouse', 2, 25.00, 2000),
(3, 'Monitor', 1, 400.00, 3000), (4, 'Keyboard', 2, 80.00, 4000),
(5, 'Tablet', 1, 600.00, 5000);
Affected Rows: 5
INSERT INTO categories_sub VALUES
(1, 'Electronics', 1000), (2, 'Accessories', 2000);
Affected Rows: 2
INSERT INTO sales_sub VALUES
(1, 1, 2, '2023-01-01', 1000), (2, 2, 10, '2023-01-02', 2000),
(3, 3, 1, '2023-01-03', 3000), (4, 1, 1, '2023-01-04', 4000),
(5, 4, 5, '2023-01-05', 5000), (6, 5, 2, '2023-01-06', 6000);
Affected Rows: 6
-- Join with aggregated subquery
SELECT
p.prod_name, p.price, sales_summary.total_quantity, sales_summary.total_sales
FROM products_sub p
INNER JOIN (
SELECT prod_id, SUM(quantity) as total_quantity, COUNT(*) as total_sales
FROM sales_sub
GROUP BY prod_id
) sales_summary ON p.prod_id = sales_summary.prod_id
ORDER BY sales_summary.total_quantity DESC;
+-----------+--------+----------------+-------------+
| prod_name | price | total_quantity | total_sales |
+-----------+--------+----------------+-------------+
| Mouse | 25.0 | 10 | 1 |
| Keyboard | 80.0 | 5 | 1 |
| Laptop | 1200.0 | 3 | 2 |
| Tablet | 600.0 | 2 | 1 |
| Monitor | 400.0 | 1 | 1 |
+-----------+--------+----------------+-------------+
-- Join with filtered subquery
SELECT
p.prod_name, c.cat_name, high_sales.quantity
FROM products_sub p
INNER JOIN categories_sub c ON p.category_id = c.cat_id
INNER JOIN (
SELECT prod_id, quantity
FROM sales_sub
WHERE quantity > 3
) high_sales ON p.prod_id = high_sales.prod_id
ORDER BY high_sales.quantity DESC;
+-----------+-------------+----------+
| prod_name | cat_name | quantity |
+-----------+-------------+----------+
| Mouse | Accessories | 10 |
| Keyboard | Accessories | 5 |
+-----------+-------------+----------+
-- Join with correlated subquery results
SELECT
p.prod_name, p.price,
(SELECT SUM(s.quantity) FROM sales_sub s WHERE s.prod_id = p.prod_id) as total_sold
FROM products_sub p
WHERE EXISTS (SELECT 1 FROM sales_sub s WHERE s.prod_id = p.prod_id)
ORDER BY total_sold DESC;
+-----------+--------+------------+
| prod_name | price | total_sold |
+-----------+--------+------------+
| Mouse | 25.0 | 10 |
| Keyboard | 80.0 | 5 |
| Laptop | 1200.0 | 3 |
| Tablet | 600.0 | 2 |
| Monitor | 400.0 | 1 |
+-----------+--------+------------+
-- Join subquery with window functions
SELECT
p.prod_name, ranked_sales.quantity, ranked_sales.sale_rank
FROM products_sub p
INNER JOIN (
SELECT
prod_id, quantity,
ROW_NUMBER() OVER (PARTITION BY prod_id ORDER BY quantity DESC) as sale_rank
FROM sales_sub
) ranked_sales ON p.prod_id = ranked_sales.prod_id
WHERE ranked_sales.sale_rank = 1
ORDER BY ranked_sales.quantity DESC, p.prod_name ASC;
+-----------+----------+-----------+
| prod_name | quantity | sale_rank |
+-----------+----------+-----------+
| Mouse | 10 | 1 |
| Keyboard | 5 | 1 |
| Laptop | 2 | 1 |
| Tablet | 2 | 1 |
| Monitor | 1 | 1 |
+-----------+----------+-----------+
-- Multiple subquery joins
SELECT
product_stats.prod_name,
product_stats.avg_price,
category_stats.category_sales
FROM (
SELECT prod_id, prod_name, AVG(price) as avg_price, category_id
FROM products_sub
GROUP BY prod_id, prod_name, category_id
) product_stats
INNER JOIN (
SELECT c.cat_id, c.cat_name, COUNT(s.sale_id) as category_sales
FROM categories_sub c
INNER JOIN products_sub p ON c.cat_id = p.category_id
INNER JOIN sales_sub s ON p.prod_id = s.prod_id
GROUP BY c.cat_id, c.cat_name
) category_stats ON product_stats.category_id = category_stats.cat_id
ORDER BY category_stats.category_sales DESC, product_stats.prod_name DESC;
+-----------+-----------+----------------+
| prod_name | avg_price | category_sales |
+-----------+-----------+----------------+
| Tablet | 600.0 | 4 |
| Monitor | 400.0 | 4 |
| Laptop | 1200.0 | 4 |
| Mouse | 25.0 | 2 |
| Keyboard | 80.0 | 2 |
+-----------+-----------+----------------+
DROP TABLE products_sub;
Affected Rows: 0
DROP TABLE categories_sub;
Affected Rows: 0
DROP TABLE sales_sub;
Affected Rows: 0

View File

@@ -0,0 +1,90 @@
-- Migrated from DuckDB test: test/sql/join/ subquery join tests
-- Tests joins involving subqueries
CREATE TABLE products_sub(prod_id INTEGER, prod_name VARCHAR, category_id INTEGER, price DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE categories_sub(cat_id INTEGER, cat_name VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE sales_sub(sale_id INTEGER, prod_id INTEGER, quantity INTEGER, sale_date DATE, ts TIMESTAMP TIME INDEX);
INSERT INTO products_sub VALUES
(1, 'Laptop', 1, 1200.00, 1000), (2, 'Mouse', 2, 25.00, 2000),
(3, 'Monitor', 1, 400.00, 3000), (4, 'Keyboard', 2, 80.00, 4000),
(5, 'Tablet', 1, 600.00, 5000);
INSERT INTO categories_sub VALUES
(1, 'Electronics', 1000), (2, 'Accessories', 2000);
INSERT INTO sales_sub VALUES
(1, 1, 2, '2023-01-01', 1000), (2, 2, 10, '2023-01-02', 2000),
(3, 3, 1, '2023-01-03', 3000), (4, 1, 1, '2023-01-04', 4000),
(5, 4, 5, '2023-01-05', 5000), (6, 5, 2, '2023-01-06', 6000);
-- Join with aggregated subquery
SELECT
p.prod_name, p.price, sales_summary.total_quantity, sales_summary.total_sales
FROM products_sub p
INNER JOIN (
SELECT prod_id, SUM(quantity) as total_quantity, COUNT(*) as total_sales
FROM sales_sub
GROUP BY prod_id
) sales_summary ON p.prod_id = sales_summary.prod_id
ORDER BY sales_summary.total_quantity DESC;
-- Join with filtered subquery
SELECT
p.prod_name, c.cat_name, high_sales.quantity
FROM products_sub p
INNER JOIN categories_sub c ON p.category_id = c.cat_id
INNER JOIN (
SELECT prod_id, quantity
FROM sales_sub
WHERE quantity > 3
) high_sales ON p.prod_id = high_sales.prod_id
ORDER BY high_sales.quantity DESC;
-- Join with correlated subquery results
SELECT
p.prod_name, p.price,
(SELECT SUM(s.quantity) FROM sales_sub s WHERE s.prod_id = p.prod_id) as total_sold
FROM products_sub p
WHERE EXISTS (SELECT 1 FROM sales_sub s WHERE s.prod_id = p.prod_id)
ORDER BY total_sold DESC;
-- Join subquery with window functions
SELECT
p.prod_name, ranked_sales.quantity, ranked_sales.sale_rank
FROM products_sub p
INNER JOIN (
SELECT
prod_id, quantity,
ROW_NUMBER() OVER (PARTITION BY prod_id ORDER BY quantity DESC) as sale_rank
FROM sales_sub
) ranked_sales ON p.prod_id = ranked_sales.prod_id
WHERE ranked_sales.sale_rank = 1
ORDER BY ranked_sales.quantity DESC, p.prod_name ASC;
-- Multiple subquery joins
SELECT
product_stats.prod_name,
product_stats.avg_price,
category_stats.category_sales
FROM (
SELECT prod_id, prod_name, AVG(price) as avg_price, category_id
FROM products_sub
GROUP BY prod_id, prod_name, category_id
) product_stats
INNER JOIN (
SELECT c.cat_id, c.cat_name, COUNT(s.sale_id) as category_sales
FROM categories_sub c
INNER JOIN products_sub p ON c.cat_id = p.category_id
INNER JOIN sales_sub s ON p.prod_id = s.prod_id
GROUP BY c.cat_id, c.cat_name
) category_stats ON product_stats.category_id = category_stats.cat_id
ORDER BY category_stats.category_sales DESC, product_stats.prod_name DESC;
DROP TABLE products_sub;
DROP TABLE categories_sub;
DROP TABLE sales_sub;

View File

@@ -0,0 +1,115 @@
-- Migrated from DuckDB test: test/sql/join/left_outer/ pattern tests
-- Tests common left join patterns
CREATE TABLE accounts(acc_id INTEGER, acc_name VARCHAR, balance DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE transactions(txn_id INTEGER, acc_id INTEGER, amount DOUBLE, txn_type VARCHAR, txn_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO accounts VALUES
(1, 'Checking', 1500.00, 1000), (2, 'Savings', 5000.00, 2000),
(3, 'Credit', -250.00, 3000), (4, 'Investment', 10000.00, 4000);
Affected Rows: 4
INSERT INTO transactions VALUES
(1, 1, -100.00, 'withdrawal', '2023-01-01', 1000),
(2, 1, 500.00, 'deposit', '2023-01-02', 2000),
(3, 2, 1000.00, 'deposit', '2023-01-01', 3000),
(4, 3, -50.00, 'purchase', '2023-01-03', 4000),
(5, 1, -25.00, 'fee', '2023-01-04', 5000);
Affected Rows: 5
-- Left join to find accounts with/without transactions
SELECT
a.acc_name, a.balance,
COUNT(t.txn_id) as transaction_count,
COALESCE(SUM(t.amount), 0) as total_activity
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
GROUP BY a.acc_id, a.acc_name, a.balance
ORDER BY transaction_count DESC;
+------------+---------+-------------------+----------------+
| acc_name | balance | transaction_count | total_activity |
+------------+---------+-------------------+----------------+
| Checking | 1500.0 | 3 | 375.0 |
| Savings | 5000.0 | 1 | 1000.0 |
| Credit | -250.0 | 1 | -50.0 |
| Investment | 10000.0 | 0 | 0.0 |
+------------+---------+-------------------+----------------+
-- Left join with date filtering
SELECT
a.acc_name,
COUNT(t.txn_id) as recent_transactions,
SUM(CASE WHEN t.amount > 0 THEN t.amount ELSE 0 END) as deposits,
SUM(CASE WHEN t.amount < 0 THEN t.amount ELSE 0 END) as withdrawals
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id AND t.txn_date >= '2023-01-02'
GROUP BY a.acc_id, a.acc_name
ORDER BY recent_transactions DESC, a.acc_name ASC;
+------------+---------------------+----------+-------------+
| acc_name | recent_transactions | deposits | withdrawals |
+------------+---------------------+----------+-------------+
| Checking | 2 | 500.0 | -25.0 |
| Credit | 1 | 0.0 | -50.0 |
| Investment | 0 | 0.0 | 0.0 |
| Savings | 0 | 0.0 | 0.0 |
+------------+---------------------+----------+-------------+
-- Left join NULL handling
SELECT
a.acc_name,
a.balance,
t.txn_id,
COALESCE(t.amount, 0) as transaction_amount,
CASE WHEN t.txn_id IS NULL THEN 'No Activity' ELSE 'Has Activity' END as status
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
ORDER BY a.acc_id, t.txn_date;
+------------+---------+--------+--------------------+--------------+
| acc_name | balance | txn_id | transaction_amount | status |
+------------+---------+--------+--------------------+--------------+
| Checking | 1500.0 | 1 | -100.0 | Has Activity |
| Checking | 1500.0 | 2 | 500.0 | Has Activity |
| Checking | 1500.0 | 5 | -25.0 | Has Activity |
| Savings | 5000.0 | 3 | 1000.0 | Has Activity |
| Credit | -250.0 | 4 | -50.0 | Has Activity |
| Investment | 10000.0 | | 0.0 | No Activity |
+------------+---------+--------+--------------------+--------------+
-- Left join with complex conditions
SELECT
a.acc_name,
COUNT(large_txn.txn_id) as large_transaction_count,
AVG(large_txn.amount) as avg_large_amount
FROM accounts a
LEFT JOIN (
SELECT * FROM transactions WHERE ABS(amount) > 100.00
) large_txn ON a.acc_id = large_txn.acc_id
GROUP BY a.acc_id, a.acc_name
ORDER BY large_transaction_count DESC, a.acc_name ASC;
+------------+-------------------------+------------------+
| acc_name | large_transaction_count | avg_large_amount |
+------------+-------------------------+------------------+
| Checking | 1 | 500.0 |
| Savings | 1 | 1000.0 |
| Credit | 0 | |
| Investment | 0 | |
+------------+-------------------------+------------------+
DROP TABLE accounts;
Affected Rows: 0
DROP TABLE transactions;
Affected Rows: 0

View File

@@ -0,0 +1,65 @@
-- Migrated from DuckDB test: test/sql/join/left_outer/ pattern tests
-- Tests common left join patterns
CREATE TABLE accounts(acc_id INTEGER, acc_name VARCHAR, balance DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE transactions(txn_id INTEGER, acc_id INTEGER, amount DOUBLE, txn_type VARCHAR, txn_date DATE, ts TIMESTAMP TIME INDEX);
INSERT INTO accounts VALUES
(1, 'Checking', 1500.00, 1000), (2, 'Savings', 5000.00, 2000),
(3, 'Credit', -250.00, 3000), (4, 'Investment', 10000.00, 4000);
INSERT INTO transactions VALUES
(1, 1, -100.00, 'withdrawal', '2023-01-01', 1000),
(2, 1, 500.00, 'deposit', '2023-01-02', 2000),
(3, 2, 1000.00, 'deposit', '2023-01-01', 3000),
(4, 3, -50.00, 'purchase', '2023-01-03', 4000),
(5, 1, -25.00, 'fee', '2023-01-04', 5000);
-- Left join to find accounts with/without transactions
SELECT
a.acc_name, a.balance,
COUNT(t.txn_id) as transaction_count,
COALESCE(SUM(t.amount), 0) as total_activity
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
GROUP BY a.acc_id, a.acc_name, a.balance
ORDER BY transaction_count DESC;
-- Left join with date filtering
SELECT
a.acc_name,
COUNT(t.txn_id) as recent_transactions,
SUM(CASE WHEN t.amount > 0 THEN t.amount ELSE 0 END) as deposits,
SUM(CASE WHEN t.amount < 0 THEN t.amount ELSE 0 END) as withdrawals
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id AND t.txn_date >= '2023-01-02'
GROUP BY a.acc_id, a.acc_name
ORDER BY recent_transactions DESC, a.acc_name ASC;
-- Left join NULL handling
SELECT
a.acc_name,
a.balance,
t.txn_id,
COALESCE(t.amount, 0) as transaction_amount,
CASE WHEN t.txn_id IS NULL THEN 'No Activity' ELSE 'Has Activity' END as status
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
ORDER BY a.acc_id, t.txn_date;
-- Left join with complex conditions
SELECT
a.acc_name,
COUNT(large_txn.txn_id) as large_transaction_count,
AVG(large_txn.amount) as avg_large_amount
FROM accounts a
LEFT JOIN (
SELECT * FROM transactions WHERE ABS(amount) > 100.00
) large_txn ON a.acc_id = large_txn.acc_id
GROUP BY a.acc_id, a.acc_name
ORDER BY large_transaction_count DESC, a.acc_name ASC;
DROP TABLE accounts;
DROP TABLE transactions;

View File

@@ -0,0 +1,67 @@
-- Migrated from DuckDB test: test/sql/join/left_outer/test_left_outer.test
-- Tests LEFT OUTER JOIN functionality
CREATE TABLE left_t (a INTEGER, b INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE right_t (a INTEGER, c INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO left_t VALUES (1, 10, 1000), (2, 20, 2000), (3, 30, 3000);
Affected Rows: 3
INSERT INTO right_t VALUES (1, 100, 4000), (2, 200, 5000), (4, 400, 6000);
Affected Rows: 3
-- Basic LEFT JOIN
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a ORDER BY left_t.a;
+---+----+---------------------+---+-----+---------------------+
| a | b | ts | a | c | ts |
+---+----+---------------------+---+-----+---------------------+
| 1 | 10 | 1970-01-01T00:00:01 | 1 | 100 | 1970-01-01T00:00:04 |
| 2 | 20 | 1970-01-01T00:00:02 | 2 | 200 | 1970-01-01T00:00:05 |
| 3 | 30 | 1970-01-01T00:00:03 | | | |
+---+----+---------------------+---+-----+---------------------+
-- LEFT JOIN with WHERE on left table
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a WHERE left_t.b > 15 ORDER BY left_t.a;
+---+----+---------------------+---+-----+---------------------+
| a | b | ts | a | c | ts |
+---+----+---------------------+---+-----+---------------------+
| 2 | 20 | 1970-01-01T00:00:02 | 2 | 200 | 1970-01-01T00:00:05 |
| 3 | 30 | 1970-01-01T00:00:03 | | | |
+---+----+---------------------+---+-----+---------------------+
-- LEFT JOIN with WHERE on joined result
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a WHERE right_t.c IS NULL ORDER BY left_t.a;
+---+----+---------------------+---+---+----+
| a | b | ts | a | c | ts |
+---+----+---------------------+---+---+----+
| 3 | 30 | 1970-01-01T00:00:03 | | | |
+---+----+---------------------+---+---+----+
-- LEFT JOIN with complex condition
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a AND left_t.b < 25 ORDER BY left_t.a;
+---+----+---------------------+---+-----+---------------------+
| a | b | ts | a | c | ts |
+---+----+---------------------+---+-----+---------------------+
| 1 | 10 | 1970-01-01T00:00:01 | 1 | 100 | 1970-01-01T00:00:04 |
| 2 | 20 | 1970-01-01T00:00:02 | 2 | 200 | 1970-01-01T00:00:05 |
| 3 | 30 | 1970-01-01T00:00:03 | | | |
+---+----+---------------------+---+-----+---------------------+
DROP TABLE right_t;
Affected Rows: 0
DROP TABLE left_t;
Affected Rows: 0

View File

@@ -0,0 +1,26 @@
-- Migrated from DuckDB test: test/sql/join/left_outer/test_left_outer.test
-- Tests LEFT OUTER JOIN functionality
CREATE TABLE left_t (a INTEGER, b INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE right_t (a INTEGER, c INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO left_t VALUES (1, 10, 1000), (2, 20, 2000), (3, 30, 3000);
INSERT INTO right_t VALUES (1, 100, 4000), (2, 200, 5000), (4, 400, 6000);
-- Basic LEFT JOIN
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a ORDER BY left_t.a;
-- LEFT JOIN with WHERE on left table
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a WHERE left_t.b > 15 ORDER BY left_t.a;
-- LEFT JOIN with WHERE on joined result
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a WHERE right_t.c IS NULL ORDER BY left_t.a;
-- LEFT JOIN with complex condition
SELECT * FROM left_t LEFT JOIN right_t ON left_t.a = right_t.a AND left_t.b < 25 ORDER BY left_t.a;
DROP TABLE right_t;
DROP TABLE left_t;

View File

@@ -0,0 +1,183 @@
-- Migrated from DuckDB test: test/sql/join/ multi-way join tests
-- Tests complex multi-table join scenarios
CREATE TABLE users_multi(user_id INTEGER, username VARCHAR, email VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE posts_multi(post_id INTEGER, user_id INTEGER, title VARCHAR, content TEXT, created_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE comments_multi(comment_id INTEGER, post_id INTEGER, user_id INTEGER, comment_text VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE likes_multi(like_id INTEGER, post_id INTEGER, user_id INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO users_multi VALUES
(1, 'alice', 'alice@example.com', 1000), (2, 'bob', 'bob@example.com', 2000),
(3, 'charlie', 'charlie@example.com', 3000), (4, 'diana', 'diana@example.com', 4000);
Affected Rows: 4
INSERT INTO posts_multi VALUES
(1, 1, 'First Post', 'Hello World', '2023-01-01', 1000),
(2, 2, 'Tech Talk', 'About databases', '2023-01-02', 2000),
(3, 1, 'Update', 'Progress report', '2023-01-03', 3000),
(4, 3, 'Discussion', 'Open topic', '2023-01-04', 4000);
Affected Rows: 4
INSERT INTO comments_multi VALUES
(1, 1, 2, 'Great post!', 1000), (2, 1, 3, 'Thanks for sharing', 2000),
(3, 2, 1, 'Very informative', 3000), (4, 3, 4, 'Keep it up', 4000),
(5, 4, 2, 'Interesting discussion', 5000);
Affected Rows: 5
INSERT INTO likes_multi VALUES
(1, 1, 2, 1000), (2, 1, 3, 2000), (3, 1, 4, 3000),
(4, 2, 1, 4000), (5, 2, 3, 5000), (6, 3, 2, 6000);
Affected Rows: 6
-- Four-way join
SELECT
u.username as author,
p.title,
c.comment_text,
commenter.username as commenter
FROM users_multi u
INNER JOIN posts_multi p ON u.user_id = p.user_id
INNER JOIN comments_multi c ON p.post_id = c.post_id
INNER JOIN users_multi commenter ON c.user_id = commenter.user_id
ORDER BY p.post_id, c.comment_id;
+---------+------------+------------------------+-----------+
| author | title | comment_text | commenter |
+---------+------------+------------------------+-----------+
| alice | First Post | Great post! | bob |
| alice | First Post | Thanks for sharing | charlie |
| bob | Tech Talk | Very informative | alice |
| alice | Update | Keep it up | diana |
| charlie | Discussion | Interesting discussion | bob |
+---------+------------+------------------------+-----------+
-- Multi-way join with aggregation
SELECT
u.username,
COUNT(DISTINCT p.post_id) as posts_created,
COUNT(DISTINCT c.comment_id) as comments_made,
COUNT(DISTINCT l.like_id) as likes_given
FROM users_multi u
LEFT JOIN posts_multi p ON u.user_id = p.user_id
LEFT JOIN comments_multi c ON u.user_id = c.user_id
LEFT JOIN likes_multi l ON u.user_id = l.user_id
GROUP BY u.user_id, u.username
ORDER BY posts_created DESC, comments_made DESC;
+----------+---------------+---------------+-------------+
| username | posts_created | comments_made | likes_given |
+----------+---------------+---------------+-------------+
| alice | 2 | 1 | 1 |
| bob | 1 | 2 | 2 |
| charlie | 1 | 1 | 2 |
| diana | 0 | 1 | 1 |
+----------+---------------+---------------+-------------+
-- Post engagement analysis
SELECT
p.title,
u.username as author,
COUNT(DISTINCT c.comment_id) as comment_count,
COUNT(DISTINCT l.like_id) as like_count,
COUNT(DISTINCT c.user_id) as unique_commenters
FROM posts_multi p
INNER JOIN users_multi u ON p.user_id = u.user_id
LEFT JOIN comments_multi c ON p.post_id = c.post_id
LEFT JOIN likes_multi l ON p.post_id = l.post_id
GROUP BY p.post_id, p.title, u.username
ORDER BY like_count DESC, comment_count DESC;
+------------+---------+---------------+------------+-------------------+
| title | author | comment_count | like_count | unique_commenters |
+------------+---------+---------------+------------+-------------------+
| First Post | alice | 2 | 3 | 2 |
| Tech Talk | bob | 1 | 2 | 1 |
| Update | alice | 1 | 1 | 1 |
| Discussion | charlie | 1 | 0 | 1 |
+------------+---------+---------------+------------+-------------------+
-- Complex multi-join with conditions
SELECT
author.username as post_author,
p.title,
commenter.username as commenter,
liker.username as liker
FROM posts_multi p
INNER JOIN users_multi author ON p.user_id = author.user_id
INNER JOIN comments_multi c ON p.post_id = c.post_id
INNER JOIN users_multi commenter ON c.user_id = commenter.user_id
INNER JOIN likes_multi l ON p.post_id = l.post_id
INNER JOIN users_multi liker ON l.user_id = liker.user_id
WHERE author.user_id != commenter.user_id
AND author.user_id != liker.user_id
ORDER BY p.post_id, commenter.user_id, liker.user_id;
+-------------+------------+-----------+---------+
| post_author | title | commenter | liker |
+-------------+------------+-----------+---------+
| alice | First Post | bob | bob |
| alice | First Post | bob | charlie |
| alice | First Post | bob | diana |
| alice | First Post | charlie | bob |
| alice | First Post | charlie | charlie |
| alice | First Post | charlie | diana |
| bob | Tech Talk | alice | alice |
| bob | Tech Talk | alice | charlie |
| alice | Update | diana | bob |
+-------------+------------+-----------+---------+
-- Multi-join with subqueries
SELECT
u.username,
popular_posts.title,
popular_posts.engagement_score
FROM users_multi u
INNER JOIN (
SELECT
p.post_id, p.user_id, p.title,
COUNT(DISTINCT l.like_id) + COUNT(DISTINCT c.comment_id) as engagement_score
FROM posts_multi p
LEFT JOIN likes_multi l ON p.post_id = l.post_id
LEFT JOIN comments_multi c ON p.post_id = c.post_id
GROUP BY p.post_id, p.user_id, p.title
HAVING COUNT(DISTINCT l.like_id) + COUNT(DISTINCT c.comment_id) > 2
) popular_posts ON u.user_id = popular_posts.user_id
ORDER BY popular_posts.engagement_score DESC;
+----------+------------+------------------+
| username | title | engagement_score |
+----------+------------+------------------+
| alice | First Post | 5 |
| bob | Tech Talk | 3 |
+----------+------------+------------------+
DROP TABLE users_multi;
Affected Rows: 0
DROP TABLE posts_multi;
Affected Rows: 0
DROP TABLE comments_multi;
Affected Rows: 0
DROP TABLE likes_multi;
Affected Rows: 0

View File

@@ -0,0 +1,110 @@
-- Migrated from DuckDB test: test/sql/join/ multi-way join tests
-- Tests complex multi-table join scenarios
CREATE TABLE users_multi(user_id INTEGER, username VARCHAR, email VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE posts_multi(post_id INTEGER, user_id INTEGER, title VARCHAR, content TEXT, created_date DATE, ts TIMESTAMP TIME INDEX);
CREATE TABLE comments_multi(comment_id INTEGER, post_id INTEGER, user_id INTEGER, comment_text VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE likes_multi(like_id INTEGER, post_id INTEGER, user_id INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO users_multi VALUES
(1, 'alice', 'alice@example.com', 1000), (2, 'bob', 'bob@example.com', 2000),
(3, 'charlie', 'charlie@example.com', 3000), (4, 'diana', 'diana@example.com', 4000);
INSERT INTO posts_multi VALUES
(1, 1, 'First Post', 'Hello World', '2023-01-01', 1000),
(2, 2, 'Tech Talk', 'About databases', '2023-01-02', 2000),
(3, 1, 'Update', 'Progress report', '2023-01-03', 3000),
(4, 3, 'Discussion', 'Open topic', '2023-01-04', 4000);
INSERT INTO comments_multi VALUES
(1, 1, 2, 'Great post!', 1000), (2, 1, 3, 'Thanks for sharing', 2000),
(3, 2, 1, 'Very informative', 3000), (4, 3, 4, 'Keep it up', 4000),
(5, 4, 2, 'Interesting discussion', 5000);
INSERT INTO likes_multi VALUES
(1, 1, 2, 1000), (2, 1, 3, 2000), (3, 1, 4, 3000),
(4, 2, 1, 4000), (5, 2, 3, 5000), (6, 3, 2, 6000);
-- Four-way join
SELECT
u.username as author,
p.title,
c.comment_text,
commenter.username as commenter
FROM users_multi u
INNER JOIN posts_multi p ON u.user_id = p.user_id
INNER JOIN comments_multi c ON p.post_id = c.post_id
INNER JOIN users_multi commenter ON c.user_id = commenter.user_id
ORDER BY p.post_id, c.comment_id;
-- Multi-way join with aggregation
SELECT
u.username,
COUNT(DISTINCT p.post_id) as posts_created,
COUNT(DISTINCT c.comment_id) as comments_made,
COUNT(DISTINCT l.like_id) as likes_given
FROM users_multi u
LEFT JOIN posts_multi p ON u.user_id = p.user_id
LEFT JOIN comments_multi c ON u.user_id = c.user_id
LEFT JOIN likes_multi l ON u.user_id = l.user_id
GROUP BY u.user_id, u.username
ORDER BY posts_created DESC, comments_made DESC;
-- Post engagement analysis
SELECT
p.title,
u.username as author,
COUNT(DISTINCT c.comment_id) as comment_count,
COUNT(DISTINCT l.like_id) as like_count,
COUNT(DISTINCT c.user_id) as unique_commenters
FROM posts_multi p
INNER JOIN users_multi u ON p.user_id = u.user_id
LEFT JOIN comments_multi c ON p.post_id = c.post_id
LEFT JOIN likes_multi l ON p.post_id = l.post_id
GROUP BY p.post_id, p.title, u.username
ORDER BY like_count DESC, comment_count DESC;
-- Complex multi-join with conditions
SELECT
author.username as post_author,
p.title,
commenter.username as commenter,
liker.username as liker
FROM posts_multi p
INNER JOIN users_multi author ON p.user_id = author.user_id
INNER JOIN comments_multi c ON p.post_id = c.post_id
INNER JOIN users_multi commenter ON c.user_id = commenter.user_id
INNER JOIN likes_multi l ON p.post_id = l.post_id
INNER JOIN users_multi liker ON l.user_id = liker.user_id
WHERE author.user_id != commenter.user_id
AND author.user_id != liker.user_id
ORDER BY p.post_id, commenter.user_id, liker.user_id;
-- Multi-join with subqueries
SELECT
u.username,
popular_posts.title,
popular_posts.engagement_score
FROM users_multi u
INNER JOIN (
SELECT
p.post_id, p.user_id, p.title,
COUNT(DISTINCT l.like_id) + COUNT(DISTINCT c.comment_id) as engagement_score
FROM posts_multi p
LEFT JOIN likes_multi l ON p.post_id = l.post_id
LEFT JOIN comments_multi c ON p.post_id = c.post_id
GROUP BY p.post_id, p.user_id, p.title
HAVING COUNT(DISTINCT l.like_id) + COUNT(DISTINCT c.comment_id) > 2
) popular_posts ON u.user_id = popular_posts.user_id
ORDER BY popular_posts.engagement_score DESC;
DROP TABLE users_multi;
DROP TABLE posts_multi;
DROP TABLE comments_multi;
DROP TABLE likes_multi;

View File

@@ -0,0 +1,87 @@
-- Migrated from DuckDB test: Multiple join scenarios
-- Tests multiple table joins
CREATE TABLE customers_multi("id" INTEGER, "name" VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE orders_multi("id" INTEGER, customer_id INTEGER, product_id INTEGER, amount DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE products_multi("id" INTEGER, "name" VARCHAR, category VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO customers_multi VALUES (1, 'Alice', 'NYC', 1000), (2, 'Bob', 'LA', 2000), (3, 'Carol', 'Chicago', 3000);
Affected Rows: 3
INSERT INTO orders_multi VALUES (101, 1, 1001, 150.0, 4000), (102, 2, 1002, 200.0, 5000), (103, 1, 1001, 150.0, 6000);
Affected Rows: 3
INSERT INTO products_multi VALUES (1001, 'Laptop', 'Electronics', 1000.0, 7000), (1002, 'Book', 'Education', 25.0, 8000);
Affected Rows: 2
-- Three table join
SELECT c."name", p."name" as product, o.amount
FROM customers_multi c
JOIN orders_multi o ON c."id" = o.customer_id
JOIN products_multi p ON o.product_id = p."id"
ORDER BY c."name", p."name";
+-------+---------+--------+
| name | product | amount |
+-------+---------+--------+
| Alice | Laptop | 150.0 |
| Alice | Laptop | 150.0 |
| Bob | Book | 200.0 |
+-------+---------+--------+
-- Multiple joins with aggregation
SELECT
c.city,
p.category,
COUNT(*) as order_count,
SUM(o.amount) as total_amount
FROM customers_multi c
JOIN orders_multi o ON c."id" = o.customer_id
JOIN products_multi p ON o.product_id = p."id"
GROUP BY c.city, p.category
ORDER BY c.city, p.category;
+------+-------------+-------------+--------------+
| city | category | order_count | total_amount |
+------+-------------+-------------+--------------+
| LA | Education | 1 | 200.0 |
| NYC | Electronics | 2 | 300.0 |
+------+-------------+-------------+--------------+
-- Mixed join types
SELECT c."name", p."name" as product, o.amount
FROM customers_multi c
LEFT JOIN orders_multi o ON c."id" = o.customer_id
INNER JOIN products_multi p ON o.product_id = p."id"
ORDER BY c."name", p."name" NULLS LAST;
+-------+---------+--------+
| name | product | amount |
+-------+---------+--------+
| Alice | Laptop | 150.0 |
| Alice | Laptop | 150.0 |
| Bob | Book | 200.0 |
+-------+---------+--------+
DROP TABLE products_multi;
Affected Rows: 0
DROP TABLE orders_multi;
Affected Rows: 0
DROP TABLE customers_multi;
Affected Rows: 0

View File

@@ -0,0 +1,46 @@
-- Migrated from DuckDB test: Multiple join scenarios
-- Tests multiple table joins
CREATE TABLE customers_multi("id" INTEGER, "name" VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE orders_multi("id" INTEGER, customer_id INTEGER, product_id INTEGER, amount DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE products_multi("id" INTEGER, "name" VARCHAR, category VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO customers_multi VALUES (1, 'Alice', 'NYC', 1000), (2, 'Bob', 'LA', 2000), (3, 'Carol', 'Chicago', 3000);
INSERT INTO orders_multi VALUES (101, 1, 1001, 150.0, 4000), (102, 2, 1002, 200.0, 5000), (103, 1, 1001, 150.0, 6000);
INSERT INTO products_multi VALUES (1001, 'Laptop', 'Electronics', 1000.0, 7000), (1002, 'Book', 'Education', 25.0, 8000);
-- Three table join
SELECT c."name", p."name" as product, o.amount
FROM customers_multi c
JOIN orders_multi o ON c."id" = o.customer_id
JOIN products_multi p ON o.product_id = p."id"
ORDER BY c."name", p."name";
-- Multiple joins with aggregation
SELECT
c.city,
p.category,
COUNT(*) as order_count,
SUM(o.amount) as total_amount
FROM customers_multi c
JOIN orders_multi o ON c."id" = o.customer_id
JOIN products_multi p ON o.product_id = p."id"
GROUP BY c.city, p.category
ORDER BY c.city, p.category;
-- Mixed join types
SELECT c."name", p."name" as product, o.amount
FROM customers_multi c
LEFT JOIN orders_multi o ON c."id" = o.customer_id
INNER JOIN products_multi p ON o.product_id = p."id"
ORDER BY c."name", p."name" NULLS LAST;
DROP TABLE products_multi;
DROP TABLE orders_multi;
DROP TABLE customers_multi;

View File

@@ -0,0 +1,60 @@
-- Migrated from DuckDB test: test/sql/join/natural/natural_join.test
-- Tests NATURAL JOIN functionality
CREATE TABLE emp_natural("id" INTEGER, "name" VARCHAR, dept_id INTEGER, ts1 TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE dept_natural(dept_id INTEGER, dept_name VARCHAR, ts2 TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO emp_natural VALUES (1, 'Alice', 10, 1000), (2, 'Bob', 20, 2000), (3, 'Carol', 10, 3000);
Affected Rows: 3
INSERT INTO dept_natural VALUES (10, 'Engineering', 4000), (20, 'Sales', 5000), (30, 'Marketing', 6000);
Affected Rows: 3
-- NATURAL JOIN (joins on common column names)
SELECT * FROM emp_natural NATURAL JOIN dept_natural ORDER BY "id";
+----+-------+---------------------+---------+-------------+---------------------+
| id | name | ts1 | dept_id | dept_name | ts2 |
+----+-------+---------------------+---------+-------------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | 10 | Engineering | 1970-01-01T00:00:04 |
| 2 | Bob | 1970-01-01T00:00:02 | 20 | Sales | 1970-01-01T00:00:05 |
| 3 | Carol | 1970-01-01T00:00:03 | 10 | Engineering | 1970-01-01T00:00:04 |
+----+-------+---------------------+---------+-------------+---------------------+
-- NATURAL LEFT JOIN
SELECT * FROM emp_natural NATURAL LEFT JOIN dept_natural ORDER BY "id";
+----+-------+---------------------+---------+-------------+---------------------+
| id | name | ts1 | dept_id | dept_name | ts2 |
+----+-------+---------------------+---------+-------------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | 10 | Engineering | 1970-01-01T00:00:04 |
| 2 | Bob | 1970-01-01T00:00:02 | 20 | Sales | 1970-01-01T00:00:05 |
| 3 | Carol | 1970-01-01T00:00:03 | 10 | Engineering | 1970-01-01T00:00:04 |
+----+-------+---------------------+---------+-------------+---------------------+
-- NATURAL RIGHT JOIN
SELECT * FROM emp_natural NATURAL RIGHT JOIN dept_natural ORDER BY dept_id;
+----+-------+---------------------+---------+-------------+---------------------+
| id | name | ts1 | dept_id | dept_name | ts2 |
+----+-------+---------------------+---------+-------------+---------------------+
| 1 | Alice | 1970-01-01T00:00:01 | 10 | Engineering | 1970-01-01T00:00:04 |
| 3 | Carol | 1970-01-01T00:00:03 | 10 | Engineering | 1970-01-01T00:00:04 |
| 2 | Bob | 1970-01-01T00:00:02 | 20 | Sales | 1970-01-01T00:00:05 |
| | | | 30 | Marketing | 1970-01-01T00:00:06 |
+----+-------+---------------------+---------+-------------+---------------------+
DROP TABLE dept_natural;
Affected Rows: 0
DROP TABLE emp_natural;
Affected Rows: 0

View File

@@ -0,0 +1,23 @@
-- Migrated from DuckDB test: test/sql/join/natural/natural_join.test
-- Tests NATURAL JOIN functionality
CREATE TABLE emp_natural("id" INTEGER, "name" VARCHAR, dept_id INTEGER, ts1 TIMESTAMP TIME INDEX);
CREATE TABLE dept_natural(dept_id INTEGER, dept_name VARCHAR, ts2 TIMESTAMP TIME INDEX);
INSERT INTO emp_natural VALUES (1, 'Alice', 10, 1000), (2, 'Bob', 20, 2000), (3, 'Carol', 10, 3000);
INSERT INTO dept_natural VALUES (10, 'Engineering', 4000), (20, 'Sales', 5000), (30, 'Marketing', 6000);
-- NATURAL JOIN (joins on common column names)
SELECT * FROM emp_natural NATURAL JOIN dept_natural ORDER BY "id";
-- NATURAL LEFT JOIN
SELECT * FROM emp_natural NATURAL LEFT JOIN dept_natural ORDER BY "id";
-- NATURAL RIGHT JOIN
SELECT * FROM emp_natural NATURAL RIGHT JOIN dept_natural ORDER BY dept_id;
DROP TABLE dept_natural;
DROP TABLE emp_natural;

View File

@@ -0,0 +1,113 @@
-- Migrated from DuckDB test: test/sql/join/natural/ advanced tests
-- Tests advanced natural join patterns
CREATE TABLE employees_nat(emp_id INTEGER, "name" VARCHAR, dept_id INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE departments_nat(dept_id INTEGER, dept_name VARCHAR, budget INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE dept_locations(dept_id INTEGER, "location" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO employees_nat VALUES
(1, 'Alice', 10, 1000), (2, 'Bob', 20, 2000), (3, 'Charlie', 10, 3000),
(4, 'Diana', 30, 4000), (5, 'Eve', 20, 5000);
Affected Rows: 5
INSERT INTO departments_nat VALUES
(10, 'Engineering', 500000, 1000), (20, 'Marketing', 300000, 2000), (30, 'Sales', 200000, 3000);
Affected Rows: 3
INSERT INTO dept_locations VALUES
(10, 'Building A', 1000), (20, 'Building B', 2000), (30, 'Building C', 3000);
Affected Rows: 3
-- Basic natural join
SELECT * FROM employees_nat NATURAL JOIN departments_nat ORDER BY emp_id;
+--------+-------+---------+-------------+--------+---------------------+
| emp_id | name | dept_id | dept_name | budget | ts |
+--------+-------+---------+-------------+--------+---------------------+
| 1 | Alice | 10 | Engineering | 500000 | 1970-01-01T00:00:01 |
| 2 | Bob | 20 | Marketing | 300000 | 1970-01-01T00:00:02 |
+--------+-------+---------+-------------+--------+---------------------+
-- Natural join with filtering
SELECT * FROM employees_nat NATURAL JOIN departments_nat
WHERE budget > 250000 ORDER BY emp_id;
+--------+-------+---------+-------------+--------+---------------------+
| emp_id | name | dept_id | dept_name | budget | ts |
+--------+-------+---------+-------------+--------+---------------------+
| 1 | Alice | 10 | Engineering | 500000 | 1970-01-01T00:00:01 |
| 2 | Bob | 20 | Marketing | 300000 | 1970-01-01T00:00:02 |
+--------+-------+---------+-------------+--------+---------------------+
-- Multi-table natural join
SELECT
emp_id, "name", dept_name, "location", budget
FROM employees_nat
NATURAL JOIN departments_nat
NATURAL JOIN dept_locations
ORDER BY emp_id;
+--------+-------+-------------+------------+--------+
| emp_id | name | dept_name | location | budget |
+--------+-------+-------------+------------+--------+
| 1 | Alice | Engineering | Building A | 500000 |
| 2 | Bob | Marketing | Building B | 300000 |
+--------+-------+-------------+------------+--------+
-- Natural join with aggregation
SELECT
dept_name,
COUNT(emp_id) as employee_count,
AVG(budget) as avg_budget,
"location"
FROM employees_nat
NATURAL JOIN departments_nat
NATURAL JOIN dept_locations
GROUP BY dept_name, "location", budget
ORDER BY employee_count DESC, dept_name ASC;
+-------------+----------------+------------+------------+
| dept_name | employee_count | avg_budget | location |
+-------------+----------------+------------+------------+
| Engineering | 1 | 500000.0 | Building A |
| Marketing | 1 | 300000.0 | Building B |
+-------------+----------------+------------+------------+
-- Natural join with expressions
SELECT
"name",
dept_name,
budget,
CASE WHEN budget > 400000 THEN 'High Budget' ELSE 'Normal Budget' END as budget_tier
FROM employees_nat NATURAL JOIN departments_nat
ORDER BY budget DESC, "name";
+-------+-------------+--------+---------------+
| name | dept_name | budget | budget_tier |
+-------+-------------+--------+---------------+
| Alice | Engineering | 500000 | High Budget |
| Bob | Marketing | 300000 | Normal Budget |
+-------+-------------+--------+---------------+
DROP TABLE employees_nat;
Affected Rows: 0
DROP TABLE departments_nat;
Affected Rows: 0
DROP TABLE dept_locations;
Affected Rows: 0

View File

@@ -0,0 +1,60 @@
-- Migrated from DuckDB test: test/sql/join/natural/ advanced tests
-- Tests advanced natural join patterns
CREATE TABLE employees_nat(emp_id INTEGER, "name" VARCHAR, dept_id INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE departments_nat(dept_id INTEGER, dept_name VARCHAR, budget INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE dept_locations(dept_id INTEGER, "location" VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO employees_nat VALUES
(1, 'Alice', 10, 1000), (2, 'Bob', 20, 2000), (3, 'Charlie', 10, 3000),
(4, 'Diana', 30, 4000), (5, 'Eve', 20, 5000);
INSERT INTO departments_nat VALUES
(10, 'Engineering', 500000, 1000), (20, 'Marketing', 300000, 2000), (30, 'Sales', 200000, 3000);
INSERT INTO dept_locations VALUES
(10, 'Building A', 1000), (20, 'Building B', 2000), (30, 'Building C', 3000);
-- Basic natural join
SELECT * FROM employees_nat NATURAL JOIN departments_nat ORDER BY emp_id;
-- Natural join with filtering
SELECT * FROM employees_nat NATURAL JOIN departments_nat
WHERE budget > 250000 ORDER BY emp_id;
-- Multi-table natural join
SELECT
emp_id, "name", dept_name, "location", budget
FROM employees_nat
NATURAL JOIN departments_nat
NATURAL JOIN dept_locations
ORDER BY emp_id;
-- Natural join with aggregation
SELECT
dept_name,
COUNT(emp_id) as employee_count,
AVG(budget) as avg_budget,
"location"
FROM employees_nat
NATURAL JOIN departments_nat
NATURAL JOIN dept_locations
GROUP BY dept_name, "location", budget
ORDER BY employee_count DESC, dept_name ASC;
-- Natural join with expressions
SELECT
"name",
dept_name,
budget,
CASE WHEN budget > 400000 THEN 'High Budget' ELSE 'Normal Budget' END as budget_tier
FROM employees_nat NATURAL JOIN departments_nat
ORDER BY budget DESC, "name";
DROP TABLE employees_nat;
DROP TABLE departments_nat;
DROP TABLE dept_locations;

View File

@@ -0,0 +1,133 @@
-- Migrated from DuckDB test: test/sql/join/full_outer/ complex tests
-- Tests complex outer join scenarios
CREATE TABLE employees(emp_id INTEGER, "name" VARCHAR, dept_id INTEGER, salary INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE departments(dept_id INTEGER, dept_name VARCHAR, manager_id INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE projects(proj_id INTEGER, proj_name VARCHAR, dept_id INTEGER, budget INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO employees VALUES
(1, 'Alice', 10, 75000, 1000), (2, 'Bob', 20, 65000, 2000),
(3, 'Charlie', 10, 80000, 3000), (4, 'Diana', 30, 70000, 4000), (5, 'Eve', NULL, 60000, 5000);
Affected Rows: 5
INSERT INTO departments VALUES
(10, 'Engineering', 1, 1000), (20, 'Marketing', 2, 2000), (40, 'HR', NULL, 3000);
Affected Rows: 3
INSERT INTO projects VALUES
(101, 'ProjectA', 10, 100000, 1000), (102, 'ProjectB', 20, 150000, 2000),
(103, 'ProjectC', 30, 75000, 3000), (104, 'ProjectD', 50, 200000, 4000);
Affected Rows: 4
-- Full outer join with multiple conditions
SELECT
e.emp_id, e."name", d.dept_id, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_id, d.dept_id;
+--------+---------+---------+-------------+
| emp_id | name | dept_id | dept_name |
+--------+---------+---------+-------------+
| 1 | Alice | 10 | Engineering |
| 2 | Bob | 20 | Marketing |
| 3 | Charlie | 10 | Engineering |
| 4 | Diana | | |
| 5 | Eve | | |
| | | 40 | HR |
+--------+---------+---------+-------------+
-- Left outer join with IS NULL filter
SELECT
e.emp_id, e."name", e.dept_id, d.dept_name
FROM employees e
LEFT OUTER JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_id IS NULL
ORDER BY e.emp_id;
+--------+-------+---------+-----------+
| emp_id | name | dept_id | dept_name |
+--------+-------+---------+-----------+
| 4 | Diana | 30 | |
| 5 | Eve | | |
+--------+-------+---------+-----------+
-- Right outer join
SELECT
e.emp_id, e."name", d.dept_id, d.dept_name
FROM employees e
RIGHT OUTER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY d.dept_id, e.emp_id;
+--------+---------+---------+-------------+
| emp_id | name | dept_id | dept_name |
+--------+---------+---------+-------------+
| 1 | Alice | 10 | Engineering |
| 3 | Charlie | 10 | Engineering |
| 2 | Bob | 20 | Marketing |
| | | 40 | HR |
+--------+---------+---------+-------------+
-- Triple outer join
SELECT
e."name", d.dept_name, p.proj_name, p.budget
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id
FULL OUTER JOIN projects p ON d.dept_id = p.dept_id
ORDER BY e.emp_id, p.proj_id;
+---------+-------------+-----------+--------+
| name | dept_name | proj_name | budget |
+---------+-------------+-----------+--------+
| Alice | Engineering | ProjectA | 100000 |
| Bob | Marketing | ProjectB | 150000 |
| Charlie | Engineering | ProjectA | 100000 |
| Diana | | | |
| Eve | | | |
| | | ProjectC | 75000 |
| | | ProjectD | 200000 |
| | HR | | |
+---------+-------------+-----------+--------+
-- Outer join with aggregation
SELECT
d.dept_name,
COUNT(e.emp_id) as employee_count,
AVG(e.salary) as avg_salary,
SUM(p.budget) as total_project_budget
FROM departments d
LEFT OUTER JOIN employees e ON d.dept_id = e.dept_id
LEFT OUTER JOIN projects p ON d.dept_id = p.dept_id
GROUP BY d.dept_name
ORDER BY d.dept_name;
+-------------+----------------+------------+----------------------+
| dept_name | employee_count | avg_salary | total_project_budget |
+-------------+----------------+------------+----------------------+
| Engineering | 2 | 77500.0 | 200000 |
| HR | 0 | | |
| Marketing | 1 | 65000.0 | 150000 |
+-------------+----------------+------------+----------------------+
DROP TABLE employees;
Affected Rows: 0
DROP TABLE departments;
Affected Rows: 0
DROP TABLE projects;
Affected Rows: 0

View File

@@ -0,0 +1,67 @@
-- Migrated from DuckDB test: test/sql/join/full_outer/ complex tests
-- Tests complex outer join scenarios
CREATE TABLE employees(emp_id INTEGER, "name" VARCHAR, dept_id INTEGER, salary INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE departments(dept_id INTEGER, dept_name VARCHAR, manager_id INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE projects(proj_id INTEGER, proj_name VARCHAR, dept_id INTEGER, budget INTEGER, ts TIMESTAMP TIME INDEX);
INSERT INTO employees VALUES
(1, 'Alice', 10, 75000, 1000), (2, 'Bob', 20, 65000, 2000),
(3, 'Charlie', 10, 80000, 3000), (4, 'Diana', 30, 70000, 4000), (5, 'Eve', NULL, 60000, 5000);
INSERT INTO departments VALUES
(10, 'Engineering', 1, 1000), (20, 'Marketing', 2, 2000), (40, 'HR', NULL, 3000);
INSERT INTO projects VALUES
(101, 'ProjectA', 10, 100000, 1000), (102, 'ProjectB', 20, 150000, 2000),
(103, 'ProjectC', 30, 75000, 3000), (104, 'ProjectD', 50, 200000, 4000);
-- Full outer join with multiple conditions
SELECT
e.emp_id, e."name", d.dept_id, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_id, d.dept_id;
-- Left outer join with IS NULL filter
SELECT
e.emp_id, e."name", e.dept_id, d.dept_name
FROM employees e
LEFT OUTER JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_id IS NULL
ORDER BY e.emp_id;
-- Right outer join
SELECT
e.emp_id, e."name", d.dept_id, d.dept_name
FROM employees e
RIGHT OUTER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY d.dept_id, e.emp_id;
-- Triple outer join
SELECT
e."name", d.dept_name, p.proj_name, p.budget
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id
FULL OUTER JOIN projects p ON d.dept_id = p.dept_id
ORDER BY e.emp_id, p.proj_id;
-- Outer join with aggregation
SELECT
d.dept_name,
COUNT(e.emp_id) as employee_count,
AVG(e.salary) as avg_salary,
SUM(p.budget) as total_project_budget
FROM departments d
LEFT OUTER JOIN employees e ON d.dept_id = e.dept_id
LEFT OUTER JOIN projects p ON d.dept_id = p.dept_id
GROUP BY d.dept_name
ORDER BY d.dept_name;
DROP TABLE employees;
DROP TABLE departments;
DROP TABLE projects;

View File

@@ -0,0 +1,113 @@
-- Migrated from DuckDB test: test/sql/join/right_outer/ pattern tests
-- Tests right join patterns
CREATE TABLE inventory(item_id INTEGER, item_name VARCHAR, stock_quantity INTEGER, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE purchase_orders(po_id INTEGER, item_id INTEGER, ordered_qty INTEGER, order_date DATE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO inventory VALUES
(1, 'Widget A', 100, 1000), (2, 'Widget B', 50, 2000), (3, 'Widget C', 0, 3000);
Affected Rows: 3
INSERT INTO purchase_orders VALUES
(1, 1, 25, '2023-01-01', 1000), (2, 2, 30, '2023-01-02', 2000),
(3, 4, 15, '2023-01-03', 3000), (4, 5, 40, '2023-01-04', 4000),
(5, 1, 10, '2023-01-05', 5000);
Affected Rows: 5
-- Right join to show all orders (including for non-inventory items)
SELECT
po.po_id, po.ordered_qty, po.order_date,
COALESCE(i.item_name, 'Unknown Item') as item_name,
COALESCE(i.stock_quantity, 0) as current_stock
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
ORDER BY po.order_date, po.po_id;
+-------+-------------+------------+--------------+---------------+
| po_id | ordered_qty | order_date | item_name | current_stock |
+-------+-------------+------------+--------------+---------------+
| 1 | 25 | 2023-01-01 | Widget A | 100 |
| 2 | 30 | 2023-01-02 | Widget B | 50 |
| 3 | 15 | 2023-01-03 | Unknown Item | 0 |
| 4 | 40 | 2023-01-04 | Unknown Item | 0 |
| 5 | 10 | 2023-01-05 | Widget A | 100 |
+-------+-------------+------------+--------------+---------------+
-- Right join with aggregation
SELECT
po.item_id,
COUNT(po.po_id) as order_count,
SUM(po.ordered_qty) as total_ordered,
COALESCE(MAX(i.stock_quantity), 0) as stock_level,
CASE WHEN i.item_id IS NULL THEN 'Not In Inventory' ELSE 'In Stock' END as inventory_status
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
GROUP BY po.item_id, i.item_id
ORDER BY order_count DESC, po.item_id ASC;
+---------+-------------+---------------+-------------+------------------+
| item_id | order_count | total_ordered | stock_level | inventory_status |
+---------+-------------+---------------+-------------+------------------+
| 1 | 2 | 35 | 100 | In Stock |
| 2 | 1 | 30 | 50 | In Stock |
| 4 | 1 | 15 | 0 | Not In Inventory |
| 5 | 1 | 40 | 0 | Not In Inventory |
+---------+-------------+---------------+-------------+------------------+
-- Right join to identify missing inventory records
SELECT
po.item_id as missing_item_id,
COUNT(*) as orders_for_missing_item,
SUM(po.ordered_qty) as total_qty_ordered
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
WHERE i.item_id IS NULL
GROUP BY po.item_id
ORDER BY total_qty_ordered DESC, po.item_id ASC;
+-----------------+-------------------------+-------------------+
| missing_item_id | orders_for_missing_item | total_qty_ordered |
+-----------------+-------------------------+-------------------+
| 5 | 1 | 40 |
| 4 | 1 | 15 |
+-----------------+-------------------------+-------------------+
-- Right join with filtering and conditions
SELECT
po.po_id,
po.item_id,
po.ordered_qty,
COALESCE(i.item_name, 'Missing from inventory') as item_description,
CASE
WHEN i.item_id IS NULL THEN 'Order for unknown item'
WHEN i.stock_quantity < po.ordered_qty THEN 'Insufficient stock'
ELSE 'Can fulfill'
END as fulfillment_status
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
ORDER BY po.order_date;
+-------+---------+-------------+------------------------+------------------------+
| po_id | item_id | ordered_qty | item_description | fulfillment_status |
+-------+---------+-------------+------------------------+------------------------+
| 1 | 1 | 25 | Widget A | Can fulfill |
| 2 | 2 | 30 | Widget B | Can fulfill |
| 3 | 4 | 15 | Missing from inventory | Order for unknown item |
| 4 | 5 | 40 | Missing from inventory | Order for unknown item |
| 5 | 1 | 10 | Widget A | Can fulfill |
+-------+---------+-------------+------------------------+------------------------+
DROP TABLE inventory;
Affected Rows: 0
DROP TABLE purchase_orders;
Affected Rows: 0

View File

@@ -0,0 +1,65 @@
-- Migrated from DuckDB test: test/sql/join/right_outer/ pattern tests
-- Tests right join patterns
CREATE TABLE inventory(item_id INTEGER, item_name VARCHAR, stock_quantity INTEGER, ts TIMESTAMP TIME INDEX);
CREATE TABLE purchase_orders(po_id INTEGER, item_id INTEGER, ordered_qty INTEGER, order_date DATE, ts TIMESTAMP TIME INDEX);
INSERT INTO inventory VALUES
(1, 'Widget A', 100, 1000), (2, 'Widget B', 50, 2000), (3, 'Widget C', 0, 3000);
INSERT INTO purchase_orders VALUES
(1, 1, 25, '2023-01-01', 1000), (2, 2, 30, '2023-01-02', 2000),
(3, 4, 15, '2023-01-03', 3000), (4, 5, 40, '2023-01-04', 4000),
(5, 1, 10, '2023-01-05', 5000);
-- Right join to show all orders (including for non-inventory items)
SELECT
po.po_id, po.ordered_qty, po.order_date,
COALESCE(i.item_name, 'Unknown Item') as item_name,
COALESCE(i.stock_quantity, 0) as current_stock
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
ORDER BY po.order_date, po.po_id;
-- Right join with aggregation
SELECT
po.item_id,
COUNT(po.po_id) as order_count,
SUM(po.ordered_qty) as total_ordered,
COALESCE(MAX(i.stock_quantity), 0) as stock_level,
CASE WHEN i.item_id IS NULL THEN 'Not In Inventory' ELSE 'In Stock' END as inventory_status
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
GROUP BY po.item_id, i.item_id
ORDER BY order_count DESC, po.item_id ASC;
-- Right join to identify missing inventory records
SELECT
po.item_id as missing_item_id,
COUNT(*) as orders_for_missing_item,
SUM(po.ordered_qty) as total_qty_ordered
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
WHERE i.item_id IS NULL
GROUP BY po.item_id
ORDER BY total_qty_ordered DESC, po.item_id ASC;
-- Right join with filtering and conditions
SELECT
po.po_id,
po.item_id,
po.ordered_qty,
COALESCE(i.item_name, 'Missing from inventory') as item_description,
CASE
WHEN i.item_id IS NULL THEN 'Order for unknown item'
WHEN i.stock_quantity < po.ordered_qty THEN 'Insufficient stock'
ELSE 'Can fulfill'
END as fulfillment_status
FROM inventory i
RIGHT JOIN purchase_orders po ON i.item_id = po.item_id
ORDER BY po.order_date;
DROP TABLE inventory;
DROP TABLE purchase_orders;

View File

@@ -0,0 +1,58 @@
-- Migrated from DuckDB test: test/sql/join/right_outer/test_right_outer.test
-- Tests RIGHT OUTER JOIN scenarios
CREATE TABLE products_right("id" INTEGER, "name" VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE inventory_right(product_id INTEGER, stock INTEGER, "warehouse" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO products_right VALUES (1, 'Laptop', 1000.0, 1000), (2, 'Mouse', 25.0, 2000);
Affected Rows: 2
INSERT INTO inventory_right VALUES (1, 5, 'WH1', 3000), (2, 10, 'WH1', 4000), (3, 15, 'WH2', 5000);
Affected Rows: 3
-- Basic RIGHT JOIN
SELECT * FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id ORDER BY i.product_id;
+----+--------+--------+---------------------+------------+-------+-----------+---------------------+
| id | name | price | ts | product_id | stock | warehouse | ts |
+----+--------+--------+---------------------+------------+-------+-----------+---------------------+
| 1 | Laptop | 1000.0 | 1970-01-01T00:00:01 | 1 | 5 | WH1 | 1970-01-01T00:00:03 |
| 2 | Mouse | 25.0 | 1970-01-01T00:00:02 | 2 | 10 | WH1 | 1970-01-01T00:00:04 |
| | | | | 3 | 15 | WH2 | 1970-01-01T00:00:05 |
+----+--------+--------+---------------------+------------+-------+-----------+---------------------+
-- RIGHT JOIN with WHERE on left table
SELECT * FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id WHERE p.price IS NULL ORDER BY i.product_id;
+----+------+-------+----+------------+-------+-----------+---------------------+
| id | name | price | ts | product_id | stock | warehouse | ts |
+----+------+-------+----+------------+-------+-----------+---------------------+
| | | | | 3 | 15 | WH2 | 1970-01-01T00:00:05 |
+----+------+-------+----+------------+-------+-----------+---------------------+
-- RIGHT JOIN with aggregation
SELECT i."warehouse", COUNT(*) as items, AVG(p.price) as avg_price
FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id
GROUP BY i."warehouse" ORDER BY i."warehouse";
+-----------+-------+-----------+
| warehouse | items | avg_price |
+-----------+-------+-----------+
| WH1 | 2 | 512.5 |
| WH2 | 1 | |
+-----------+-------+-----------+
DROP TABLE inventory_right;
Affected Rows: 0
DROP TABLE products_right;
Affected Rows: 0

View File

@@ -0,0 +1,25 @@
-- Migrated from DuckDB test: test/sql/join/right_outer/test_right_outer.test
-- Tests RIGHT OUTER JOIN scenarios
CREATE TABLE products_right("id" INTEGER, "name" VARCHAR, price DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE inventory_right(product_id INTEGER, stock INTEGER, "warehouse" VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO products_right VALUES (1, 'Laptop', 1000.0, 1000), (2, 'Mouse', 25.0, 2000);
INSERT INTO inventory_right VALUES (1, 5, 'WH1', 3000), (2, 10, 'WH1', 4000), (3, 15, 'WH2', 5000);
-- Basic RIGHT JOIN
SELECT * FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id ORDER BY i.product_id;
-- RIGHT JOIN with WHERE on left table
SELECT * FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id WHERE p.price IS NULL ORDER BY i.product_id;
-- RIGHT JOIN with aggregation
SELECT i."warehouse", COUNT(*) as items, AVG(p.price) as avg_price
FROM products_right p RIGHT JOIN inventory_right i ON p."id" = i.product_id
GROUP BY i."warehouse" ORDER BY i."warehouse";
DROP TABLE inventory_right;
DROP TABLE products_right;

View File

@@ -0,0 +1,90 @@
-- Migrated from DuckDB test: Self join scenarios
-- Tests self join operations
CREATE TABLE employees_self(
"id" INTEGER,
"name" VARCHAR,
manager_id INTEGER,
salary INTEGER,
ts TIMESTAMP TIME INDEX
);
Affected Rows: 0
INSERT INTO employees_self VALUES
(1, 'CEO', NULL, 100000, 1000),
(2, 'Manager1', 1, 80000, 2000),
(3, 'Manager2', 1, 75000, 3000),
(4, 'Employee1', 2, 50000, 4000),
(5, 'Employee2', 2, 55000, 5000),
(6, 'Employee3', 3, 48000, 6000);
Affected Rows: 6
-- Basic self join to get employee-manager pairs
SELECT e."name" as employee, m."name" as manager
FROM employees_self e
LEFT JOIN employees_self m ON e.manager_id = m."id"
ORDER BY e."id";
+-----------+----------+
| employee | manager |
+-----------+----------+
| CEO | |
| Manager1 | CEO |
| Manager2 | CEO |
| Employee1 | Manager1 |
| Employee2 | Manager1 |
| Employee3 | Manager2 |
+-----------+----------+
-- Self join to find employees earning more than their manager
SELECT e."name" as employee, e.salary, m."name" as manager, m.salary as manager_salary
FROM employees_self e
JOIN employees_self m ON e.manager_id = m."id"
WHERE e.salary > m.salary
ORDER BY e."name";
++
++
-- Self join to find colleagues (same manager)
SELECT e1."name" as employee1, e2."name" as employee2, m."name" as shared_manager
FROM employees_self e1
JOIN employees_self e2 ON e1.manager_id = e2.manager_id AND e1."id" < e2."id"
JOIN employees_self m ON e1.manager_id = m."id"
ORDER BY shared_manager, employee1;
+-----------+-----------+----------------+
| employee1 | employee2 | shared_manager |
+-----------+-----------+----------------+
| Manager1 | Manager2 | CEO |
| Employee1 | Employee2 | Manager1 |
+-----------+-----------+----------------+
-- Hierarchical query using self join
SELECT
e."name" as employee,
e.salary,
m."name" as manager,
COUNT(sub."id") as direct_reports
FROM employees_self e
LEFT JOIN employees_self m ON e.manager_id = m."id"
LEFT JOIN employees_self sub ON e."id" = sub.manager_id
GROUP BY e."id", e."name", e.salary, m."name"
ORDER BY e."id";
+-----------+--------+----------+----------------+
| employee | salary | manager | direct_reports |
+-----------+--------+----------+----------------+
| CEO | 100000 | | 2 |
| Manager1 | 80000 | CEO | 2 |
| Manager2 | 75000 | CEO | 1 |
| Employee1 | 50000 | Manager1 | 0 |
| Employee2 | 55000 | Manager1 | 0 |
| Employee3 | 48000 | Manager2 | 0 |
+-----------+--------+----------+----------------+
DROP TABLE employees_self;
Affected Rows: 0

View File

@@ -0,0 +1,52 @@
-- Migrated from DuckDB test: Self join scenarios
-- Tests self join operations
CREATE TABLE employees_self(
"id" INTEGER,
"name" VARCHAR,
manager_id INTEGER,
salary INTEGER,
ts TIMESTAMP TIME INDEX
);
INSERT INTO employees_self VALUES
(1, 'CEO', NULL, 100000, 1000),
(2, 'Manager1', 1, 80000, 2000),
(3, 'Manager2', 1, 75000, 3000),
(4, 'Employee1', 2, 50000, 4000),
(5, 'Employee2', 2, 55000, 5000),
(6, 'Employee3', 3, 48000, 6000);
-- Basic self join to get employee-manager pairs
SELECT e."name" as employee, m."name" as manager
FROM employees_self e
LEFT JOIN employees_self m ON e.manager_id = m."id"
ORDER BY e."id";
-- Self join to find employees earning more than their manager
SELECT e."name" as employee, e.salary, m."name" as manager, m.salary as manager_salary
FROM employees_self e
JOIN employees_self m ON e.manager_id = m."id"
WHERE e.salary > m.salary
ORDER BY e."name";
-- Self join to find colleagues (same manager)
SELECT e1."name" as employee1, e2."name" as employee2, m."name" as shared_manager
FROM employees_self e1
JOIN employees_self e2 ON e1.manager_id = e2.manager_id AND e1."id" < e2."id"
JOIN employees_self m ON e1.manager_id = m."id"
ORDER BY shared_manager, employee1;
-- Hierarchical query using self join
SELECT
e."name" as employee,
e.salary,
m."name" as manager,
COUNT(sub."id") as direct_reports
FROM employees_self e
LEFT JOIN employees_self m ON e.manager_id = m."id"
LEFT JOIN employees_self sub ON e."id" = sub.manager_id
GROUP BY e."id", e."name", e.salary, m."name"
ORDER BY e."id";
DROP TABLE employees_self;

View File

@@ -0,0 +1,125 @@
-- Migrated from DuckDB test: test/sql/join/ USING clause tests
-- Tests USING clause join syntax
CREATE TABLE orders_using(order_id INTEGER, customer_id INTEGER, total DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE customers_using(customer_id INTEGER, customer_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE payments_using(payment_id INTEGER, order_id INTEGER, amount DOUBLE, "method" VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO orders_using VALUES
(1, 101, 250.00, 1000), (2, 102, 180.00, 2000), (3, 101, 420.00, 3000), (4, 103, 95.00, 4000);
Affected Rows: 4
INSERT INTO customers_using VALUES
(101, 'John Doe', 'NYC', 1000), (102, 'Jane Smith', 'LA', 2000), (103, 'Bob Wilson', 'Chicago', 3000);
Affected Rows: 3
INSERT INTO payments_using VALUES
(1, 1, 250.00, 'Credit', 1000), (2, 2, 180.00, 'Debit', 2000),
(3, 3, 420.00, 'Credit', 3000), (4, 4, 95.00, 'Cash', 4000);
Affected Rows: 4
-- Basic USING clause join
SELECT order_id, customer_name, total
FROM orders_using
INNER JOIN customers_using USING (customer_id)
ORDER BY order_id;
+----------+---------------+-------+
| order_id | customer_name | total |
+----------+---------------+-------+
| 1 | John Doe | 250.0 |
| 2 | Jane Smith | 180.0 |
| 3 | John Doe | 420.0 |
| 4 | Bob Wilson | 95.0 |
+----------+---------------+-------+
-- Multiple USING clause joins
SELECT o.order_id, c.customer_name, p.amount, p."method"
FROM orders_using o
INNER JOIN customers_using c USING (customer_id)
INNER JOIN payments_using p USING (order_id)
ORDER BY o.order_id;
+----------+---------------+--------+--------+
| order_id | customer_name | amount | method |
+----------+---------------+--------+--------+
| 1 | John Doe | 250.0 | Credit |
| 2 | Jane Smith | 180.0 | Debit |
| 3 | John Doe | 420.0 | Credit |
| 4 | Bob Wilson | 95.0 | Cash |
+----------+---------------+--------+--------+
-- LEFT JOIN with USING
SELECT c.customer_name, o.order_id, o.total
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
ORDER BY c.customer_id, o.order_id;
+---------------+----------+-------+
| customer_name | order_id | total |
+---------------+----------+-------+
| John Doe | 1 | 250.0 |
| John Doe | 3 | 420.0 |
| Jane Smith | 2 | 180.0 |
| Bob Wilson | 4 | 95.0 |
+---------------+----------+-------+
-- USING with aggregation
SELECT
c.city,
COUNT(o.order_id) as order_count,
SUM(o.total) as total_sales
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
GROUP BY c.city
ORDER BY total_sales DESC;
+---------+-------------+-------------+
| city | order_count | total_sales |
+---------+-------------+-------------+
| NYC | 2 | 670.0 |
| LA | 1 | 180.0 |
| Chicago | 1 | 95.0 |
+---------+-------------+-------------+
-- USING with complex expressions
SELECT
c.customer_name,
COUNT(o.order_id) as order_count,
COALESCE(SUM(o.total), 0) as total_spent
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
GROUP BY c.customer_id, c.customer_name
HAVING COUNT(o.order_id) != 0
ORDER BY total_spent DESC;
+---------------+-------------+-------------+
| customer_name | order_count | total_spent |
+---------------+-------------+-------------+
| John Doe | 2 | 670.0 |
| Jane Smith | 1 | 180.0 |
| Bob Wilson | 1 | 95.0 |
+---------------+-------------+-------------+
DROP TABLE orders_using;
Affected Rows: 0
DROP TABLE customers_using;
Affected Rows: 0
DROP TABLE payments_using;
Affected Rows: 0

View File

@@ -0,0 +1,64 @@
-- Migrated from DuckDB test: test/sql/join/ USING clause tests
-- Tests USING clause join syntax
CREATE TABLE orders_using(order_id INTEGER, customer_id INTEGER, total DOUBLE, ts TIMESTAMP TIME INDEX);
CREATE TABLE customers_using(customer_id INTEGER, customer_name VARCHAR, city VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE payments_using(payment_id INTEGER, order_id INTEGER, amount DOUBLE, "method" VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO orders_using VALUES
(1, 101, 250.00, 1000), (2, 102, 180.00, 2000), (3, 101, 420.00, 3000), (4, 103, 95.00, 4000);
INSERT INTO customers_using VALUES
(101, 'John Doe', 'NYC', 1000), (102, 'Jane Smith', 'LA', 2000), (103, 'Bob Wilson', 'Chicago', 3000);
INSERT INTO payments_using VALUES
(1, 1, 250.00, 'Credit', 1000), (2, 2, 180.00, 'Debit', 2000),
(3, 3, 420.00, 'Credit', 3000), (4, 4, 95.00, 'Cash', 4000);
-- Basic USING clause join
SELECT order_id, customer_name, total
FROM orders_using
INNER JOIN customers_using USING (customer_id)
ORDER BY order_id;
-- Multiple USING clause joins
SELECT o.order_id, c.customer_name, p.amount, p."method"
FROM orders_using o
INNER JOIN customers_using c USING (customer_id)
INNER JOIN payments_using p USING (order_id)
ORDER BY o.order_id;
-- LEFT JOIN with USING
SELECT c.customer_name, o.order_id, o.total
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
ORDER BY c.customer_id, o.order_id;
-- USING with aggregation
SELECT
c.city,
COUNT(o.order_id) as order_count,
SUM(o.total) as total_sales
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
GROUP BY c.city
ORDER BY total_sales DESC;
-- USING with complex expressions
SELECT
c.customer_name,
COUNT(o.order_id) as order_count,
COALESCE(SUM(o.total), 0) as total_spent
FROM customers_using c
LEFT JOIN orders_using o USING (customer_id)
GROUP BY c.customer_id, c.customer_name
HAVING COUNT(o.order_id) != 0
ORDER BY total_spent DESC;
DROP TABLE orders_using;
DROP TABLE customers_using;
DROP TABLE payments_using;

View File

@@ -0,0 +1,84 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_using_join.test
-- Tests JOIN USING clause
CREATE TABLE users_join(user_id INTEGER, username VARCHAR, email VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
CREATE TABLE orders_join(order_id INTEGER, user_id INTEGER, amount DOUBLE, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO users_join VALUES (1, 'alice', 'alice@test.com', 1000), (2, 'bob', 'bob@test.com', 2000);
Affected Rows: 2
INSERT INTO orders_join VALUES (101, 1, 150.0, 3000), (102, 1, 200.0, 4000), (103, 2, 75.0, 5000);
Affected Rows: 3
-- JOIN USING (automatically joins on common column)
SELECT * FROM users_join JOIN orders_join USING (user_id) ORDER BY order_id;
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| username | email | ts | order_id | user_id | amount | ts |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| alice | alice@test.com | 1970-01-01T00:00:01 | 101 | 1 | 150.0 | 1970-01-01T00:00:03 |
| alice | alice@test.com | 1970-01-01T00:00:01 | 102 | 1 | 200.0 | 1970-01-01T00:00:04 |
| bob | bob@test.com | 1970-01-01T00:00:02 | 103 | 2 | 75.0 | 1970-01-01T00:00:05 |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
-- LEFT JOIN USING
SELECT * FROM users_join LEFT JOIN orders_join USING (user_id) ORDER BY user_id, order_id NULLS LAST;
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| username | email | ts | order_id | user_id | amount | ts |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| alice | alice@test.com | 1970-01-01T00:00:01 | 101 | 1 | 150.0 | 1970-01-01T00:00:03 |
| alice | alice@test.com | 1970-01-01T00:00:01 | 102 | 1 | 200.0 | 1970-01-01T00:00:04 |
| bob | bob@test.com | 1970-01-01T00:00:02 | 103 | 2 | 75.0 | 1970-01-01T00:00:05 |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
-- JOIN USING with WHERE
SELECT * FROM users_join JOIN orders_join USING (user_id) WHERE amount > 100 ORDER BY amount;
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| username | email | ts | order_id | user_id | amount | ts |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
| alice | alice@test.com | 1970-01-01T00:00:01 | 101 | 1 | 150.0 | 1970-01-01T00:00:03 |
| alice | alice@test.com | 1970-01-01T00:00:01 | 102 | 1 | 200.0 | 1970-01-01T00:00:04 |
+----------+----------------+---------------------+----------+---------+--------+---------------------+
-- Multiple table JOIN USING
CREATE TABLE user_profiles(user_id INTEGER, age INTEGER, city VARCHAR, ts TIMESTAMP TIME INDEX);
Affected Rows: 0
INSERT INTO user_profiles VALUES (1, 25, 'NYC', 6000), (2, 30, 'LA', 7000);
Affected Rows: 2
SELECT * FROM users_join
JOIN orders_join USING (user_id)
JOIN user_profiles USING (user_id)
ORDER BY order_id;
+----------+----------------+---------------------+----------+---------+--------+---------------------+---------+-----+------+---------------------+
| username | email | ts | order_id | user_id | amount | ts | user_id | age | city | ts |
+----------+----------------+---------------------+----------+---------+--------+---------------------+---------+-----+------+---------------------+
| alice | alice@test.com | 1970-01-01T00:00:01 | 101 | 1 | 150.0 | 1970-01-01T00:00:03 | 1 | 25 | NYC | 1970-01-01T00:00:06 |
| alice | alice@test.com | 1970-01-01T00:00:01 | 102 | 1 | 200.0 | 1970-01-01T00:00:04 | 1 | 25 | NYC | 1970-01-01T00:00:06 |
| bob | bob@test.com | 1970-01-01T00:00:02 | 103 | 2 | 75.0 | 1970-01-01T00:00:05 | 2 | 30 | LA | 1970-01-01T00:00:07 |
+----------+----------------+---------------------+----------+---------+--------+---------------------+---------+-----+------+---------------------+
DROP TABLE user_profiles;
Affected Rows: 0
DROP TABLE orders_join;
Affected Rows: 0
DROP TABLE users_join;
Affected Rows: 0

View File

@@ -0,0 +1,34 @@
-- Migrated from DuckDB test: test/sql/join/inner/test_using_join.test
-- Tests JOIN USING clause
CREATE TABLE users_join(user_id INTEGER, username VARCHAR, email VARCHAR, ts TIMESTAMP TIME INDEX);
CREATE TABLE orders_join(order_id INTEGER, user_id INTEGER, amount DOUBLE, ts TIMESTAMP TIME INDEX);
INSERT INTO users_join VALUES (1, 'alice', 'alice@test.com', 1000), (2, 'bob', 'bob@test.com', 2000);
INSERT INTO orders_join VALUES (101, 1, 150.0, 3000), (102, 1, 200.0, 4000), (103, 2, 75.0, 5000);
-- JOIN USING (automatically joins on common column)
SELECT * FROM users_join JOIN orders_join USING (user_id) ORDER BY order_id;
-- LEFT JOIN USING
SELECT * FROM users_join LEFT JOIN orders_join USING (user_id) ORDER BY user_id, order_id NULLS LAST;
-- JOIN USING with WHERE
SELECT * FROM users_join JOIN orders_join USING (user_id) WHERE amount > 100 ORDER BY amount;
-- Multiple table JOIN USING
CREATE TABLE user_profiles(user_id INTEGER, age INTEGER, city VARCHAR, ts TIMESTAMP TIME INDEX);
INSERT INTO user_profiles VALUES (1, 25, 'NYC', 6000), (2, 30, 'LA', 7000);
SELECT * FROM users_join
JOIN orders_join USING (user_id)
JOIN user_profiles USING (user_id)
ORDER BY order_id;
DROP TABLE user_profiles;
DROP TABLE orders_join;
DROP TABLE users_join;