[{"data":1,"prerenderedAt":1305},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-queries":3},{"id":4,"title":5,"body":6,"description":1296,"extension":1297,"meta":1298,"navigation":1299,"path":1300,"redirect":1301,"seo":1302,"stem":1303,"__hash__":1304},"docs\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-queries.md","Federated Queries - User Guide",{"type":7,"value":8,"toc":1263},"minimark",[9,13,17,22,38,42,59,63,119,126,131,151,154,175,179,182,251,255,259,300,306,310,340,344,352,382,386,427,431,460,464,516,520,523,542,546,549,566,569,599,603,614,662,665,674,678,681,704,707,739,754,802,806,816,819,822,826,829,858,861,864,876,879,1015,1025,1079,1082,1086,1106,1110,1137,1141,1145,1148,1166,1172,1176,1182,1186,1196,1200,1203,1207,1210,1214,1217,1241,1245,1259],[10,11,5],"h1",{"id":12},"federated-queries-user-guide",[14,15,16],"p",{},"Federated queries let you execute one SQL statement across multiple sources — databases, local files, and S3-compatible storage — from a single SQL Console session.",[18,19,21],"h2",{"id":20},"what-federated-queries-are-for","What federated queries are for",[23,24,25,29,32,35],"ul",{},[26,27,28],"li",{},"joining data from multiple databases",[26,30,31],{},"combining database tables with local files or S3-backed files",[26,33,34],{},"comparing data across providers (e.g., AWS S3 vs DigitalOcean Spaces)",[26,36,37],{},"validating multi-source logic before turning the result into a stream workflow",[18,39,41],{"id":40},"limitations","Limitations",[23,43,44,47,50,53,56],{},[26,45,46],{},"Federated queries run through DuckDB, which may differ from native database behavior",[26,48,49],{},"Not all providers and engines behave identically — use explicit casts when types differ across sources",[26,51,52],{},"Federated queries are read-only",[26,54,55],{},"Query execution is time-limited; narrow long-running checks with filters or smaller ranges",[26,57,58],{},"The SQL Console pages federated results from the server, but each cross-source page is still a fresh query execution. Use exports or stream workflows when you need to move large result sets.",[18,60,62],{"id":61},"setting-up-a-multi-source-session","Setting up a multi-source session",[64,65,66,74,85,102,105,112],"ol",{},[26,67,68,69,73],{},"Open the ",[70,71,72],"strong",{},"SQL Console"," from Data Explorer.",[26,75,76,77,80,81,84],{},"Click ",[70,78,79],{},"Manage sources"," in the top-right corner. This opens the ",[70,82,83],{},"Query Session"," panel.",[26,86,87,88],{},"The panel lists available connections in two sections:\n",[23,89,90,96],{},[26,91,92,95],{},[70,93,94],{},"DATABASES"," — PostgreSQL, MySQL, and other database connections",[26,97,98,101],{},[70,99,100],{},"FILES"," — local file connections and S3-compatible storage (DigitalOcean Spaces, MinIO, etc.)",[26,103,104],{},"Check two or more connections to select them.",[26,106,107,108,111],{},"For database connections, pick a database from the dropdown that appears below the selected connection. Use ",[70,109,110],{},"+ DB"," to add another database from the same connection.",[26,113,114,115,118],{},"Use ",[70,116,117],{},"+ Add"," at the top of the section to create a new connection if needed.",[14,120,121,122,125],{},"When more than one source is selected, the console switches to multi-source (DuckDB) mode automatically. The header updates to show ",[70,123,124],{},"\"Multi-source • N sources\""," with alias badges for each selected source.",[127,128,130],"h3",{"id":129},"aliases","Aliases",[14,132,133,134,137,138,142,143,146,147,150],{},"Each selected source gets an ",[70,135,136],{},"auto-generated alias"," based on its connection type — for example, ",[139,140,141],"code",{},"my1"," for MySQL, ",[139,144,145],{},"pg1"," for PostgreSQL, ",[139,148,149],{},"aws"," for S3. Aliases can be edited inline in the Query Session panel.",[14,152,153],{},"Alias rules:",[23,155,156,159,162],{},[26,157,158],{},"Must start with a letter",[26,160,161],{},"Letters, numbers, and underscores only",[26,163,164,165,167,168,167,170,167,172],{},"Keep them short and readable: ",[139,166,145],{},", ",[139,169,141],{},[139,171,149],{},[139,173,174],{},"do",[18,176,178],{"id":177},"naming-conventions","Naming conventions",[14,180,181],{},"In multi-source mode, qualify all table references with aliases:",[183,184,185,201],"table",{},[186,187,188],"thead",{},[189,190,191,195,198],"tr",{},[192,193,194],"th",{},"Source type",[192,196,197],{},"Pattern",[192,199,200],{},"Example",[202,203,204,220,235],"tbody",{},[189,205,206,210,215],{},[207,208,209],"td",{},"PostgreSQL",[207,211,212],{},[139,213,214],{},"alias.schema.table",[207,216,217],{},[139,218,219],{},"pg1.public.actor",[189,221,222,225,230],{},[207,223,224],{},"MySQL",[207,226,227],{},[139,228,229],{},"alias.database.table",[207,231,232],{},[139,233,234],{},"my1.sakila.film",[189,236,237,240,246],{},[207,238,239],{},"S3 \u002F files",[207,241,242,245],{},[139,243,244],{},"read_*"," functions with alias scheme",[207,247,248],{},[139,249,250],{},"read_parquet('aws:\u002F\u002Fbucket\u002Fpath\u002F*.parquet')",[18,252,254],{"id":253},"examples","Examples",[127,256,258],{"id":257},"cross-database-join-mysql-postgresql","Cross-database join (MySQL + PostgreSQL)",[260,261,266],"pre",{"className":262,"code":263,"language":264,"meta":265,"style":265},"language-sql shiki shiki-themes github-light github-dark","SELECT p.first_name, p.last_name, m.title\nFROM my1.sakila.film AS m\nJOIN pg1.public.film_actor AS fa ON m.film_id = fa.film_id\nJOIN pg1.public.actor AS p ON p.actor_id = fa.actor_id\nWHERE m.title = 'ACE GOLDFINGER';\n","sql","",[139,267,268,276,282,288,294],{"__ignoreMap":265},[269,270,273],"span",{"class":271,"line":272},"line",1,[269,274,275],{},"SELECT p.first_name, p.last_name, m.title\n",[269,277,279],{"class":271,"line":278},2,[269,280,281],{},"FROM my1.sakila.film AS m\n",[269,283,285],{"class":271,"line":284},3,[269,286,287],{},"JOIN pg1.public.film_actor AS fa ON m.film_id = fa.film_id\n",[269,289,291],{"class":271,"line":290},4,[269,292,293],{},"JOIN pg1.public.actor AS p ON p.actor_id = fa.actor_id\n",[269,295,297],{"class":271,"line":296},5,[269,298,299],{},"WHERE m.title = 'ACE GOLDFINGER';\n",[301,302],"themed-image",{"alt":303,"dark":304,"light":305},"Federated query results showing a JOIN between PostgreSQL and MySQL sources with pagination controls","\u002Fimages\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-query-results-dark.png","\u002Fimages\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-query-results-light.png",[127,307,309],{"id":308},"database-s3-join","Database + S3 join",[260,311,313],{"className":262,"code":312,"language":264,"meta":265,"style":265},"SELECT c.id, c.email, o.total\nFROM pg1.public.customers c\nJOIN read_parquet('aws:\u002F\u002Fanalytics\u002Forders\u002F*.parquet') o\n  ON c.id = o.customer_id\nLIMIT 100;\n",[139,314,315,320,325,330,335],{"__ignoreMap":265},[269,316,317],{"class":271,"line":272},[269,318,319],{},"SELECT c.id, c.email, o.total\n",[269,321,322],{"class":271,"line":278},[269,323,324],{},"FROM pg1.public.customers c\n",[269,326,327],{"class":271,"line":284},[269,328,329],{},"JOIN read_parquet('aws:\u002F\u002Fanalytics\u002Forders\u002F*.parquet') o\n",[269,331,332],{"class":271,"line":290},[269,333,334],{},"  ON c.id = o.customer_id\n",[269,336,337],{"class":271,"line":296},[269,338,339],{},"LIMIT 100;\n",[127,341,343],{"id":342},"query-two-s3-providers","Query two S3 providers",[14,345,346,347,167,349,351],{},"Assign each S3 connection an alias (e.g., ",[139,348,149],{},[139,350,174],{},"), then use the alias as the URL scheme:",[260,353,355],{"className":262,"code":354,"language":264,"meta":265,"style":265},"SELECT a.actor_id, a.first_name AS aws_name, b.first_name AS do_name\nFROM read_parquet('aws:\u002F\u002Fmy-bucket\u002Fsakila\u002Factor\u002F*.parquet') a\nJOIN read_parquet('do:\u002F\u002Fmy-bucket\u002Fsakila\u002Factor\u002F*.parquet') b\n  ON a.actor_id = b.actor_id\nLIMIT 50;\n",[139,356,357,362,367,372,377],{"__ignoreMap":265},[269,358,359],{"class":271,"line":272},[269,360,361],{},"SELECT a.actor_id, a.first_name AS aws_name, b.first_name AS do_name\n",[269,363,364],{"class":271,"line":278},[269,365,366],{},"FROM read_parquet('aws:\u002F\u002Fmy-bucket\u002Fsakila\u002Factor\u002F*.parquet') a\n",[269,368,369],{"class":271,"line":284},[269,370,371],{},"JOIN read_parquet('do:\u002F\u002Fmy-bucket\u002Fsakila\u002Factor\u002F*.parquet') b\n",[269,373,374],{"class":271,"line":290},[269,375,376],{},"  ON a.actor_id = b.actor_id\n",[269,378,379],{"class":271,"line":296},[269,380,381],{},"LIMIT 50;\n",[127,383,385],{"id":384},"union-across-s3-providers","UNION across S3 providers",[260,387,389],{"className":262,"code":388,"language":264,"meta":265,"style":265},"SELECT 'AWS' AS source, actor_id, first_name, last_name\nFROM read_parquet('aws:\u002F\u002Fbucket\u002Factor\u002F*.parquet')\nUNION ALL\nSELECT 'DO' AS source, actor_id, first_name, last_name\nFROM read_parquet('do:\u002F\u002Fbucket\u002Factor\u002F*.parquet')\nORDER BY actor_id\nLIMIT 100;\n",[139,390,391,396,401,406,411,416,422],{"__ignoreMap":265},[269,392,393],{"class":271,"line":272},[269,394,395],{},"SELECT 'AWS' AS source, actor_id, first_name, last_name\n",[269,397,398],{"class":271,"line":278},[269,399,400],{},"FROM read_parquet('aws:\u002F\u002Fbucket\u002Factor\u002F*.parquet')\n",[269,402,403],{"class":271,"line":284},[269,404,405],{},"UNION ALL\n",[269,407,408],{"class":271,"line":290},[269,409,410],{},"SELECT 'DO' AS source, actor_id, first_name, last_name\n",[269,412,413],{"class":271,"line":296},[269,414,415],{},"FROM read_parquet('do:\u002F\u002Fbucket\u002Factor\u002F*.parquet')\n",[269,417,419],{"class":271,"line":418},6,[269,420,421],{},"ORDER BY actor_id\n",[269,423,425],{"class":271,"line":424},7,[269,426,339],{},[127,428,430],{"id":429},"database-local-file","Database + local file",[260,432,434],{"className":262,"code":433,"language":264,"meta":265,"style":265},"SELECT db.film_id, db.title, ratings.rating\nFROM pg1.public.film db\nJOIN read_parquet('\u002Fdata\u002Fratings.parquet') ratings\n  ON db.film_id = ratings.film_id\nLIMIT 100;\n",[139,435,436,441,446,451,456],{"__ignoreMap":265},[269,437,438],{"class":271,"line":272},[269,439,440],{},"SELECT db.film_id, db.title, ratings.rating\n",[269,442,443],{"class":271,"line":278},[269,444,445],{},"FROM pg1.public.film db\n",[269,447,448],{"class":271,"line":284},[269,449,450],{},"JOIN read_parquet('\u002Fdata\u002Fratings.parquet') ratings\n",[269,452,453],{"class":271,"line":290},[269,454,455],{},"  ON db.film_id = ratings.film_id\n",[269,457,458],{"class":271,"line":296},[269,459,339],{},[127,461,463],{"id":462},"three-way-join","Three-way join",[260,465,467],{"className":262,"code":466,"language":264,"meta":265,"style":265},"SELECT\n  m.title AS mysql_title,\n  p.title AS postgres_title,\n  csv.title AS file_title\nFROM my1.sakila.film m\nJOIN pg1.public.film p ON m.film_id = p.film_id\nJOIN read_csv_auto('\u002Fdata\u002Ffilm.csv') csv ON m.film_id = csv.film_id\nWHERE m.title LIKE 'A%'\nLIMIT 10;\n",[139,468,469,474,479,484,489,494,499,504,510],{"__ignoreMap":265},[269,470,471],{"class":271,"line":272},[269,472,473],{},"SELECT\n",[269,475,476],{"class":271,"line":278},[269,477,478],{},"  m.title AS mysql_title,\n",[269,480,481],{"class":271,"line":284},[269,482,483],{},"  p.title AS postgres_title,\n",[269,485,486],{"class":271,"line":290},[269,487,488],{},"  csv.title AS file_title\n",[269,490,491],{"class":271,"line":296},[269,492,493],{},"FROM my1.sakila.film m\n",[269,495,496],{"class":271,"line":418},[269,497,498],{},"JOIN pg1.public.film p ON m.film_id = p.film_id\n",[269,500,501],{"class":271,"line":424},[269,502,503],{},"JOIN read_csv_auto('\u002Fdata\u002Ffilm.csv') csv ON m.film_id = csv.film_id\n",[269,505,507],{"class":271,"line":506},8,[269,508,509],{},"WHERE m.title LIKE 'A%'\n",[269,511,513],{"class":271,"line":512},9,[269,514,515],{},"LIMIT 10;\n",[127,517,519],{"id":518},"file-only-query","File-only query",[14,521,522],{},"You can query files in a multi-source session even when the query does not use a database table:",[260,524,526],{"className":262,"code":525,"language":264,"meta":265,"style":265},"SELECT *\nFROM read_parquet('\u002Fdata\u002Fanalytics.parquet')\nLIMIT 100;\n",[139,527,528,533,538],{"__ignoreMap":265},[269,529,530],{"class":271,"line":272},[269,531,532],{},"SELECT *\n",[269,534,535],{"class":271,"line":278},[269,536,537],{},"FROM read_parquet('\u002Fdata\u002Fanalytics.parquet')\n",[269,539,540],{"class":271,"line":284},[269,541,339],{},[18,543,545],{"id":544},"supported-file-readers","Supported file readers",[14,547,548],{},"Any DuckDB file reader that accepts a URL string works with S3 aliases:",[23,550,551,556,561],{},[26,552,553],{},[139,554,555],{},"read_parquet('alias:\u002F\u002Fbucket\u002Fpath\u002F*.parquet')",[26,557,558],{},[139,559,560],{},"read_csv_auto('alias:\u002F\u002Fbucket\u002Fpath\u002F*.csv')",[26,562,563],{},[139,564,565],{},"read_json_auto('alias:\u002F\u002Fbucket\u002Fpath\u002F*.json')",[14,567,568],{},"Glob patterns work for local files and S3-style paths:",[260,570,572],{"className":262,"code":571,"language":264,"meta":265,"style":265},"SELECT COUNT(*) AS rows\nFROM read_parquet('\u002Fdata\u002Fexports\u002F*.parquet');\n\nSELECT COUNT(*) AS rows\nFROM read_parquet('aws:\u002F\u002Fbucket\u002Fdata\u002F**\u002F*.parquet');\n",[139,573,574,579,584,590,594],{"__ignoreMap":265},[269,575,576],{"class":271,"line":272},[269,577,578],{},"SELECT COUNT(*) AS rows\n",[269,580,581],{"class":271,"line":278},[269,582,583],{},"FROM read_parquet('\u002Fdata\u002Fexports\u002F*.parquet');\n",[269,585,586],{"class":271,"line":284},[269,587,589],{"emptyLinePlaceholder":588},true,"\n",[269,591,592],{"class":271,"line":290},[269,593,578],{},[269,595,596],{"class":271,"line":296},[269,597,598],{},"FROM read_parquet('aws:\u002F\u002Fbucket\u002Fdata\u002F**\u002F*.parquet');\n",[18,600,602],{"id":601},"sql-templates","SQL templates",[14,604,605,606,609,610,613],{},"The ",[70,607,608],{},"Templates"," panel (",[139,611,612],{},"Ctrl+J",") provides context-aware snippets for federated mode. When multiple sources are selected, templates are organized into sections:",[23,615,616,622,652],{},[26,617,618,621],{},[70,619,620],{},"Joins"," — cross-database JOIN, UNION, database+S3 JOIN, database+file JOIN, S3+S3 JOIN",[26,623,624,627,628,167,631,634,635],{},[70,625,626],{},"Databases"," — grouped by alias (e.g., ",[139,629,630],{},"my1 (MySQL)",[139,632,633],{},"pg1 (PostgreSQL)","), each with:\n",[23,636,637,640,647],{},[26,638,639],{},"Starter query for that alias",[26,641,642,643,646],{},"List namespaces (using ",[139,644,645],{},"duckdb_tables()",")",[26,648,649,650,646],{},"List tables (using ",[139,651,645],{},[26,653,654,657,658,661],{},[70,655,656],{},"Session"," — ",[139,659,660],{},"SHOW DATABASES;"," to list all attached aliases",[14,663,664],{},"Templates are generated dynamically based on the selected connections and their aliases. A search field at the top of the panel filters across all sections.",[14,666,667,668,673],{},"See ",[669,670,672],"a",{"href":671},"\u002Fdocs\u002Fdatabase-explorer\u002Fsql-console#templates","SQL Console — Templates"," for full details.",[18,675,677],{"id":676},"preview-and-inspect-safely","Preview and inspect safely",[14,679,680],{},"For exploration, start with a small result and increase the range only after the shape is correct:",[260,682,684],{"className":262,"code":683,"language":264,"meta":265,"style":265},"SELECT *\nFROM pg1.public.orders\nWHERE order_date >= DATE '2026-01-01'\nLIMIT 100;\n",[139,685,686,690,695,700],{"__ignoreMap":265},[269,687,688],{"class":271,"line":272},[269,689,532],{},[269,691,692],{"class":271,"line":278},[269,693,694],{},"FROM pg1.public.orders\n",[269,696,697],{"class":271,"line":284},[269,698,699],{},"WHERE order_date >= DATE '2026-01-01'\n",[269,701,702],{"class":271,"line":290},[269,703,339],{},[14,705,706],{},"For cross-source joins, filter each side and project only columns used by the result:",[260,708,710],{"className":262,"code":709,"language":264,"meta":265,"style":265},"SELECT c.id, c.email, o.total\nFROM pg1.public.customers c\nJOIN my1.shop.orders o ON CAST(o.customer_id AS INTEGER) = c.id\nWHERE c.created_at >= DATE '2026-01-01'\n  AND o.created_at >= '2026-01-01'\nLIMIT 100;\n",[139,711,712,716,720,725,730,735],{"__ignoreMap":265},[269,713,714],{"class":271,"line":272},[269,715,319],{},[269,717,718],{"class":271,"line":278},[269,719,324],{},[269,721,722],{"class":271,"line":284},[269,723,724],{},"JOIN my1.shop.orders o ON CAST(o.customer_id AS INTEGER) = c.id\n",[269,726,727],{"class":271,"line":290},[269,728,729],{},"WHERE c.created_at >= DATE '2026-01-01'\n",[269,731,732],{"class":271,"line":296},[269,733,734],{},"  AND o.created_at >= '2026-01-01'\n",[269,736,737],{"class":271,"line":418},[269,738,339],{},[14,740,741,742,745,746,749,750,753],{},"Use branch parentheses when each side of a ",[139,743,744],{},"UNION ALL"," has its own ",[139,747,748],{},"ORDER BY"," or ",[139,751,752],{},"LIMIT",":",[260,755,757],{"className":262,"code":756,"language":264,"meta":265,"style":265},"(SELECT 'Postgres' AS source, film_id, title\n FROM pg1.public.film\n WHERE title LIKE 'A%'\n LIMIT 5)\nUNION ALL\n(SELECT 'MySQL' AS source, film_id, title\n FROM my1.sakila.film\n WHERE title LIKE 'A%'\n LIMIT 5);\n",[139,758,759,764,769,774,779,783,788,793,797],{"__ignoreMap":265},[269,760,761],{"class":271,"line":272},[269,762,763],{},"(SELECT 'Postgres' AS source, film_id, title\n",[269,765,766],{"class":271,"line":278},[269,767,768],{}," FROM pg1.public.film\n",[269,770,771],{"class":271,"line":284},[269,772,773],{}," WHERE title LIKE 'A%'\n",[269,775,776],{"class":271,"line":290},[269,777,778],{}," LIMIT 5)\n",[269,780,781],{"class":271,"line":296},[269,782,405],{},[269,784,785],{"class":271,"line":418},[269,786,787],{},"(SELECT 'MySQL' AS source, film_id, title\n",[269,789,790],{"class":271,"line":424},[269,791,792],{}," FROM my1.sakila.film\n",[269,794,795],{"class":271,"line":506},[269,796,773],{},[269,798,799],{"class":271,"line":512},[269,800,801],{}," LIMIT 5);\n",[18,803,805],{"id":804},"paging-large-result-sets","Paging large result sets",[14,807,808,809,811,812,815],{},"The multi-source SQL Console uses the same results footer as direct database\ntables. Changing the page size or using Next\u002FPrevious re-runs the query with\n",[139,810,752],{}," \u002F ",[139,813,814],{},"OFFSET"," applied to the SQL itself.",[14,817,818],{},"For simple single-source queries, this is usually cheap because DuckDB can push\nthe page boundary into the source. For cross-source joins, each page\nre-executes the full federated query, so keep filters selective and select only\nthe columns you need.",[14,820,821],{},"The footer can show \"of more\" instead of an exact total. That is intentional:\nexact totals require a separate count over the unwrapped query and can be as\nexpensive as another full federated execution.",[18,823,825],{"id":824},"reduce-data-movement-with-source-side-queries","Reduce data movement with source-side queries",[14,827,828],{},"Regular federated SQL is the default path for exploration, previews, row-by-row comparisons, and joins:",[260,830,832],{"className":262,"code":831,"language":264,"meta":265,"style":265},"SELECT m.id, m.total, p.total\nFROM my1.shop.orders m\nJOIN pg1.public.orders p ON m.id = p.id\nWHERE m.created_at >= '2026-01-01'\nLIMIT 100;\n",[139,833,834,839,844,849,854],{"__ignoreMap":265},[269,835,836],{"class":271,"line":272},[269,837,838],{},"SELECT m.id, m.total, p.total\n",[269,840,841],{"class":271,"line":278},[269,842,843],{},"FROM my1.shop.orders m\n",[269,845,846],{"class":271,"line":284},[269,847,848],{},"JOIN pg1.public.orders p ON m.id = p.id\n",[269,850,851],{"class":271,"line":290},[269,852,853],{},"WHERE m.created_at >= '2026-01-01'\n",[269,855,856],{"class":271,"line":296},[269,857,339],{},[14,859,860],{},"DuckDB attaches the selected sources, pushes simple filters and column selection down where it can, and performs the cross-source work locally. In this path, only the rows and columns needed by the query should be read from each source.",[14,862,863],{},"For large validation queries, go one step further when each source database can calculate the final check itself: return the aggregate result instead of returning the matching rows. DuckDB's MySQL and PostgreSQL scanner extensions expose passthrough table functions:",[23,865,866,871],{},[26,867,868],{},[139,869,870],{},"mysql_query('alias', 'source SQL')",[26,872,873],{},[139,874,875],{},"postgres_query('alias', 'source SQL')",[14,877,878],{},"Those functions run the inner SQL inside the selected source database and return only the result rows to DuckDB. Use this for counts, sums, min\u002Fmax checks, grouped summaries, and checksum-style validation.",[260,880,882],{"className":262,"code":881,"language":264,"meta":265,"style":265},"-- Replace: your_table, public.your_table, text_column, amount_column, id.\nSELECT\n  mysql_stats.row_count AS mysql_rows,\n  pg_stats.row_count AS pg_rows,\n  mysql_stats.text_chars AS mysql_text_chars,\n  pg_stats.text_chars AS pg_text_chars,\n  mysql_stats.amount_sum AS mysql_amount_sum,\n  pg_stats.amount_sum AS pg_amount_sum\nFROM mysql_query(\n  'my1',\n  'SELECT COUNT(*) AS row_count,\n          SUM(CHAR_LENGTH(text_column)) AS text_chars,\n          SUM(amount_column) AS amount_sum\n   FROM your_table\n   WHERE id \u003C= 1000000'\n) mysql_stats\nCROSS JOIN postgres_query(\n  'pg1',\n  'SELECT COUNT(*) AS row_count,\n          SUM(LENGTH(text_column)) AS text_chars,\n          SUM(amount_column) AS amount_sum\n   FROM public.your_table\n   WHERE id \u003C= 1000000'\n) pg_stats;\n",[139,883,884,889,893,898,903,908,913,918,923,928,934,940,946,952,958,964,970,976,982,987,993,998,1004,1009],{"__ignoreMap":265},[269,885,886],{"class":271,"line":272},[269,887,888],{},"-- Replace: your_table, public.your_table, text_column, amount_column, id.\n",[269,890,891],{"class":271,"line":278},[269,892,473],{},[269,894,895],{"class":271,"line":284},[269,896,897],{},"  mysql_stats.row_count AS mysql_rows,\n",[269,899,900],{"class":271,"line":290},[269,901,902],{},"  pg_stats.row_count AS pg_rows,\n",[269,904,905],{"class":271,"line":296},[269,906,907],{},"  mysql_stats.text_chars AS mysql_text_chars,\n",[269,909,910],{"class":271,"line":418},[269,911,912],{},"  pg_stats.text_chars AS pg_text_chars,\n",[269,914,915],{"class":271,"line":424},[269,916,917],{},"  mysql_stats.amount_sum AS mysql_amount_sum,\n",[269,919,920],{"class":271,"line":506},[269,921,922],{},"  pg_stats.amount_sum AS pg_amount_sum\n",[269,924,925],{"class":271,"line":512},[269,926,927],{},"FROM mysql_query(\n",[269,929,931],{"class":271,"line":930},10,[269,932,933],{},"  'my1',\n",[269,935,937],{"class":271,"line":936},11,[269,938,939],{},"  'SELECT COUNT(*) AS row_count,\n",[269,941,943],{"class":271,"line":942},12,[269,944,945],{},"          SUM(CHAR_LENGTH(text_column)) AS text_chars,\n",[269,947,949],{"class":271,"line":948},13,[269,950,951],{},"          SUM(amount_column) AS amount_sum\n",[269,953,955],{"class":271,"line":954},14,[269,956,957],{},"   FROM your_table\n",[269,959,961],{"class":271,"line":960},15,[269,962,963],{},"   WHERE id \u003C= 1000000'\n",[269,965,967],{"class":271,"line":966},16,[269,968,969],{},") mysql_stats\n",[269,971,973],{"class":271,"line":972},17,[269,974,975],{},"CROSS JOIN postgres_query(\n",[269,977,979],{"class":271,"line":978},18,[269,980,981],{},"  'pg1',\n",[269,983,985],{"class":271,"line":984},19,[269,986,939],{},[269,988,990],{"class":271,"line":989},20,[269,991,992],{},"          SUM(LENGTH(text_column)) AS text_chars,\n",[269,994,996],{"class":271,"line":995},21,[269,997,951],{},[269,999,1001],{"class":271,"line":1000},22,[269,1002,1003],{},"   FROM public.your_table\n",[269,1005,1007],{"class":271,"line":1006},23,[269,1008,963],{},[269,1010,1012],{"class":271,"line":1011},24,[269,1013,1014],{},") pg_stats;\n",[14,1016,1017,1018,1020,1021,1024],{},"The SQL Console includes this pattern in ",[70,1019,608],{}," as ",[70,1022,1023],{},"Source-side aggregate check"," when both MySQL and PostgreSQL aliases are selected.",[183,1026,1027,1043],{},[186,1028,1029],{},[189,1030,1031,1034],{},[192,1032,1033],{},"Use regular federated SQL when...",[192,1035,114,1036,811,1039,1042],{},[139,1037,1038],{},"mysql_query()",[139,1040,1041],{},"postgres_query()"," when...",[202,1044,1045,1053,1063,1071],{},[189,1046,1047,1050],{},[207,1048,1049],{},"You need joined rows in the result",[207,1051,1052],{},"You need a count, sum, min\u002Fmax, checksum, or grouped summary",[189,1054,1055,1060],{},[207,1056,1057,1058],{},"You are exploring data with ",[139,1059,752],{},[207,1061,1062],{},"The source database can return a small aggregate result",[189,1064,1065,1068],{},[207,1066,1067],{},"The join decides which rows count",[207,1069,1070],{},"The aggregate is source-local and safe before any join",[189,1072,1073,1076],{},[207,1074,1075],{},"You are joining files\u002FS3 with database rows",[207,1077,1078],{},"You can return one aggregate result instead of matching source rows",[14,1080,1081],{},"Only aggregate before a join when you already know the join will not change the row set or duplicate rows, such as a unique key comparison where the ID ranges are known to match.",[18,1083,1085],{"id":1084},"mode-transitions","Mode transitions",[23,1087,1088,1094,1100],{},[26,1089,1090,1093],{},[70,1091,1092],{},"Single-source → multi-source",": adding a second source switches to DuckDB mode automatically. Existing SQL is not rewritten.",[26,1095,1096,1099],{},[70,1097,1098],{},"Multi-source → single-source",": removing sources back to one switches back to direct mode automatically.",[26,1101,1102,1105],{},[70,1103,1104],{},"Explicit rewrite",": when a starter query needs alias-qualified naming, the console offers a \"Rewrite starter SQL to federated naming\" action.",[18,1107,1109],{"id":1108},"practical-rules","Practical rules",[23,1111,1112,1115,1122,1128,1131,1134],{},[26,1113,1114],{},"Always qualify table references with aliases in multi-source mode",[26,1116,1117,1118,1121],{},"Unqualified references (e.g., ",[139,1119,1120],{},"SELECT * FROM actor",") will fail in multi-source mode",[26,1123,1124,1125,1127],{},"Add ",[139,1126,752],{}," while exploring, then remove it only when the output size is intentional",[26,1129,1130],{},"Filter each source early and select only the columns needed by the result",[26,1132,1133],{},"Use explicit casts when types differ across sources",[26,1135,1136],{},"S3 alias routing covers S3-compatible providers; GCS and Azure are not currently supported with alias routing",[18,1138,1140],{"id":1139},"troubleshooting","Troubleshooting",[127,1142,1144],{"id":1143},"table-not-found","\"Table not found\"",[14,1146,1147],{},"Check that the table uses the correct alias-qualified name:",[23,1149,1150,1159],{},[26,1151,1152,1153,1155,1156],{},"PostgreSQL: ",[139,1154,214],{},", for example ",[139,1157,1158],{},"pg1.public.film",[26,1160,1161,1162,1155,1164],{},"MySQL: ",[139,1163,229],{},[139,1165,234],{},[14,1167,1168,1169,1171],{},"Also verify that the source is selected in ",[70,1170,79],{},".",[127,1173,1175],{"id":1174},"connection-not-attached","\"Connection not attached\"",[14,1177,1178,1179,1181],{},"The query references an alias that is not active in the current session. Open ",[70,1180,79],{},", select the source, and check that the alias in the panel matches the alias used in SQL.",[127,1183,1185],{"id":1184},"unknown-s3-aliases-in-query","\"unknown S3 alias(es) in query\"",[14,1187,1188,1189,1192,1193,1195],{},"Your SQL uses a scheme like ",[139,1190,1191],{},"aws:\u002F\u002F...",", but no source with alias ",[139,1194,149],{}," is selected. Open the Query Session panel, select the S3 connection, and set its alias to match.",[127,1197,1199],{"id":1198},"access-denied-403-signature-errors","Access denied \u002F 403 \u002F signature errors",[14,1201,1202],{},"Credentials or region\u002Fendpoint mismatch. Verify the S3 connection credentials. For DigitalOcean\u002FMinIO, ensure the endpoint is set correctly. For AWS, ensure the region matches the bucket's region.",[127,1204,1206],{"id":1205},"works-for-aws-fails-for-spacesminio","Works for AWS, fails for Spaces\u002FMinIO",[14,1208,1209],{},"Endpoint and URL style differences. Confirm the connection's endpoint is set (Spaces\u002FMinIO usually require it). If your provider requires path-style access, configure the connection accordingly.",[127,1211,1213],{"id":1212},"query-timeout","Query timeout",[14,1215,1216],{},"Start by checking whether the query is moving more data than intended:",[23,1218,1219,1222,1225,1231,1234],{},[26,1220,1221],{},"add filters to each source",[26,1223,1224],{},"select fewer columns",[26,1226,1227,1228,1230],{},"use ",[139,1229,752],{}," for previews",[26,1232,1233],{},"aggregate before returning rows when the final answer is a count, sum, min\u002Fmax, or checksum",[26,1235,1227,1236,811,1238,1240],{},[139,1237,1038],{},[139,1239,1041],{}," when the source can safely reduce rows before DuckDB joins the results",[18,1242,1244],{"id":1243},"related-docs","Related docs",[23,1246,1247,1253],{},[26,1248,1249,1252],{},[669,1250,72],{"href":1251},"\u002Fdocs\u002Fdatabase-explorer\u002Fsql-console"," — Query editor, autocomplete, diagnostics",[26,1254,1255],{},[669,1256,1258],{"href":1257},"\u002Fdocs\u002Fapi\u002Ffederated-queries","Federated Query API Workflows",[1260,1261,1262],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":265,"searchDepth":278,"depth":278,"links":1264},[1265,1266,1267,1270,1271,1280,1281,1282,1283,1284,1285,1286,1287,1295],{"id":20,"depth":278,"text":21},{"id":40,"depth":278,"text":41},{"id":61,"depth":278,"text":62,"children":1268},[1269],{"id":129,"depth":284,"text":130},{"id":177,"depth":278,"text":178},{"id":253,"depth":278,"text":254,"children":1272},[1273,1274,1275,1276,1277,1278,1279],{"id":257,"depth":284,"text":258},{"id":308,"depth":284,"text":309},{"id":342,"depth":284,"text":343},{"id":384,"depth":284,"text":385},{"id":429,"depth":284,"text":430},{"id":462,"depth":284,"text":463},{"id":518,"depth":284,"text":519},{"id":544,"depth":278,"text":545},{"id":601,"depth":278,"text":602},{"id":676,"depth":278,"text":677},{"id":804,"depth":278,"text":805},{"id":824,"depth":278,"text":825},{"id":1084,"depth":278,"text":1085},{"id":1108,"depth":278,"text":1109},{"id":1139,"depth":278,"text":1140,"children":1288},[1289,1290,1291,1292,1293,1294],{"id":1143,"depth":284,"text":1144},{"id":1174,"depth":284,"text":1175},{"id":1184,"depth":284,"text":1185},{"id":1198,"depth":284,"text":1199},{"id":1205,"depth":284,"text":1206},{"id":1212,"depth":284,"text":1213},{"id":1243,"depth":278,"text":1244},"Query across multiple databases and file-backed sources from a single SQL workflow in DBConvert Streams.","md",{},false,"\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-queries",null,{"title":5,"description":1296},"docs\u002Fdatabase-explorer\u002Ffederated-queries","v2C9ikX82Z3zyifclSzp-0YdLnxcQ-jhrSixNd6YXoI",1787648540040]