[{"data":1,"prerenderedAt":697},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fonline-viewers":3},{"id":4,"title":5,"body":6,"description":688,"extension":689,"meta":690,"navigation":691,"path":692,"redirect":693,"seo":694,"stem":695,"__hash__":696},"docs\u002Fdocs\u002Fonline-viewers.md","Online Viewers",{"type":7,"value":8,"toc":675},"minimark",[9,14,18,66,69,74,91,94,101,105,112,153,159,166,186,191,194,223,234,246,252,256,267,283,286,291,302,306,309,357,364,368,375,380,384,397,403,408,411,472,487,492,495,509,520,524,537,542,570,577,581,636,643,647,671],[10,11,13],"h1",{"id":12},"online-viewers","Online viewers",[15,16,17],"p",{},"Three pages that open a data file in a browser tab and let you query it. No account, nothing\ninstalled, and the file never leaves the tab.",[19,20,21,36,50],"ul",{},[22,23,24,31,32],"li",{},[25,26,30],"a",{"href":27,"rel":28},"https:\u002F\u002Fstreams.dbconvert.com\u002Fparquet-viewer",[29],"nofollow","Parquet Viewer"," — ",[33,34,35],"code",{},".parquet",[22,37,38,31,43,46,47],{},[25,39,42],{"href":40,"rel":41},"https:\u002F\u002Fstreams.dbconvert.com\u002Fjsonl-viewer",[29],"JSONL Viewer",[33,44,45],{},".jsonl",", ",[33,48,49],{},".ndjson",[22,51,52,31,57,46,60,46,63],{},[25,53,56],{"href":54,"rel":55},"https:\u002F\u002Fstreams.dbconvert.com\u002Fsqlite-viewer",[29],"SQLite Viewer",[33,58,59],{},".db",[33,61,62],{},".sqlite",[33,64,65],{},".sqlite3",[15,67,68],{},"All three behave the same way, so this one page is the reference for all of them.",[70,71,73],"h2",{"id":72},"open-a-file","Open a file",[75,76,77,80,88],"ol",{},[22,78,79],{},"Go to the viewer for your format.",[22,81,82,83,87],{},"Drag the file onto the page, or click ",[84,85,86],"strong",{},"Choose files",".",[22,89,90],{},"The rows appear straight away, and the SQL editor is one tab away.",[15,92,93],{},"Nothing is uploaded. The file is read inside the browser tab, so there is no server copy to worry\nabout and closing the tab leaves nothing behind — which is what makes it safe to open a file you\nwere sent rather than one you own.",[15,95,96,97,100],{},"You can look and query, but not change: the viewers run ",[33,98,99],{},"SELECT"," only. The file you opened is the\nfile you still have.",[70,102,104],{"id":103},"opening-several-files-at-once","Opening several files at once",[15,106,107,108,111],{},"The Parquet and JSONL viewers hold several files of their format open together. ",[84,109,110],{},"Each file becomes\na named view",", so the SQL reads like SQL rather than like a path:",[113,114,119],"pre",{"className":115,"code":116,"language":117,"meta":118,"style":118},"language-sql shiki shiki-themes github-light github-dark","SELECT c.country, count(*) AS orders, round(sum(o.amount), 2) AS total\nFROM orders o\nJOIN customers c USING (customer_id)\nGROUP BY 1\nORDER BY total DESC\n","sql","",[33,120,121,129,135,141,147],{"__ignoreMap":118},[122,123,126],"span",{"class":124,"line":125},"line",1,[122,127,128],{},"SELECT c.country, count(*) AS orders, round(sum(o.amount), 2) AS total\n",[122,130,132],{"class":124,"line":131},2,[122,133,134],{},"FROM orders o\n",[122,136,138],{"class":124,"line":137},3,[122,139,140],{},"JOIN customers c USING (customer_id)\n",[122,142,144],{"class":124,"line":143},4,[122,145,146],{},"GROUP BY 1\n",[122,148,150],{"class":124,"line":149},5,[122,151,152],{},"ORDER BY total DESC\n",[154,155],"themed-image",{"alt":156,"dark":157,"light":158},"The SQL tab of the Parquet viewer with a query joining two open files, the result grid below it, and the result columns listed beside the grid","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-parquet-join-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-parquet-join-light.png",[15,160,161,162,165],{},"Stacking files that should have been one file is the same idea with a set operation. ",[33,163,164],{},"BY NAME","\nmatches columns by name instead of position, which is what saves you when the writer added a column\nhalfway through the quarter:",[113,167,169],{"className":115,"code":168,"language":117,"meta":118,"style":118},"SELECT * FROM january\nUNION ALL BY NAME\nSELECT * FROM february\n",[33,170,171,176,181],{"__ignoreMap":118},[122,172,173],{"class":124,"line":125},[122,174,175],{},"SELECT * FROM january\n",[122,177,178],{"class":124,"line":131},[122,179,180],{},"UNION ALL BY NAME\n",[122,182,183],{"class":124,"line":137},[122,184,185],{},"SELECT * FROM february\n",[187,188,190],"h3",{"id":189},"where-the-view-names-come-from","Where the view names come from",[15,192,193],{},"The name is derived from the filename, because a filename is usually not a SQL identifier:",[19,195,196,206,213],{},[22,197,198,199,202,203,205],{},"everything that is not a letter, a digit or ",[33,200,201],{},"_"," becomes ",[33,204,201],{},";",[22,207,208,209,212],{},"a name that would start with a digit gets an ",[33,210,211],{},"f_"," in front of it;",[22,214,215,216,219,220,87],{},"a second file whose name collides gets ",[33,217,218],{},"_2",", then ",[33,221,222],{},"_3",[15,224,225,226,229,230,233],{},"So ",[33,227,228],{},"2026 orders-final.parquet"," is queried as ",[33,231,232],{},"f_2026_orders_final",". You never have to work this out —\nthe sidebar shows the name each file was given, and clicking a file writes the query for you.",[15,235,236,237,240,241,245],{},"Dropping the ",[84,238,239],{},"same"," file twice does not open it twice: the copy already open is selected instead.\nTwo ",[242,243,244],"em",{},"different"," files that happen to share a name both open, under names that differ.",[15,247,248,249,251],{},"The SQLite viewer opens one database at a time — a ",[33,250,59],{}," file already contains many tables, and they\njoin without any of this.",[70,253,255],{"id":254},"two-tabs-browsing-and-querying","Two tabs: browsing and querying",[15,257,258,259,262,263,266],{},"The right-hand pane has a ",[84,260,261],{},"Data"," tab and a ",[84,264,265],{},"SQL"," tab, and they do not share state.",[19,268,269,274],{},[22,270,271,273],{},[84,272,261],{}," previews whatever the sidebar has selected — a file in the Parquet and JSONL viewers, a\ntable or view in the SQLite one. Clicking in the tree brings this tab forward and shows the rows.",[22,275,276,278,279,282],{},[84,277,265],{}," holds the editor and its result. ",[84,280,281],{},"Clicking a file never touches it",", so a query you are\npart-way through writing cannot be destroyed by a click in the tree.",[15,284,285],{},"Switching tabs re-runs nothing; both grids keep their sort, column widths and scroll position.",[154,287],{"alt":288,"dark":289,"light":290},"The Data tab of the Parquet viewer with two files in the sidebar tree, one expanded to its columns, and the file information panel below the tree","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-parquet-data-tab-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-parquet-data-tab-light.png",[15,292,293,294,297,298,301],{},"Press ",[84,295,296],{},"Ctrl+Enter"," (",[84,299,300],{},"⌘+Enter",") in the editor to run the query.",[70,303,305],{"id":304},"the-file-information-panel","The file information panel",[15,307,308],{},"Under the file tree, a panel describes whatever is selected. It changes with the selection rather\nthan describing the workspace, because with several files open a single header would be describing\nonly one of them.",[310,311,312,325],"table",{},[313,314,315],"thead",{},[316,317,318,322],"tr",{},[319,320,321],"th",{},"Viewer",[319,323,324],{},"What the panel shows",[326,327,328,337,345],"tbody",{},[316,329,330,334],{},[331,332,333],"td",{},"Parquet",[331,335,336],{},"Rows, row groups, compression codec, uncompressed size, and the writer that produced the file",[316,338,339,342],{},[331,340,341],{},"JSON Lines",[331,343,344],{},"The per-line validation result: how many lines are valid data, and how many failed to parse",[316,346,347,350],{},[331,348,349],{},"SQLite",[331,351,352,353,356],{},"Rows, indexes, page size, page count, unused pages, text encoding, user version, application id, the SQLite version that wrote it, and a ",[33,354,355],{},"PRAGMA integrity_check"," result",[15,358,359,360,363],{},"For Parquet, each column in the tree expands to the statistics the file carries for it — minimum,\nmaximum, null count and share, compressed size on disk and uncompressed size. Those numbers belong\nto the file, which is why they appear under the file and not next to the result of a query: after a\n",[33,361,362],{},"GROUP BY"," the minimum of a source column describes the file, not the rows on screen.",[70,365,367],{"id":366},"why-json-lines-needs-its-own-viewer","Why JSON Lines needs its own viewer",[15,369,370,371,374],{},"JSON Lines is one JSON value per line, which is what makes it streamable and also what makes a\nsingle bad line break a whole-file parse. So validation is per line: you get the count of valid data\nlines, the count and position of the ones that failed, and column types inferred ",[84,372,373],{},"across the whole\nfile"," rather than guessed from the first record — nested objects included, and keys a JSON viewer\nusually mangles, like ones with dots or spaces in them.",[154,376],{"alt":377,"dark":378,"light":379},"The JSONL viewer showing a JSON Lines file rendered as a table, with the validation result in the file information panel","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-jsonl-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-jsonl-light.png",[70,381,383],{"id":382},"binary-and-media-values","Binary and media values",[15,385,386,387,396],{},"This applies wherever the data actually carries bytes: ",[84,388,389,392,393,395],{},[33,390,391],{},"BLOB"," columns in SQLite, and ",[33,394,391],{},"\ncolumns in Parquet",". JSON Lines has no binary type, so the case does not arise there — a\nbase64 string in a JSONL file is text, and is shown as text.",[15,398,399,400,402],{},"A ",[33,401,391],{}," is not printed as bytes. The cell shows its size and what the bytes turn out to be, and\nimages small enough to be cheap get a thumbnail:",[154,404],{"alt":405,"dark":406,"light":407},"A SQLite table of media blobs where each cell shows the size and detected kind — JPEG image, AVIF image, MP4 video, MP3 audio — with thumbnails on the small images","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-sqlite-blobs-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-sqlite-blobs-light.png",[15,409,410],{},"The kind is worked out from the value itself, not from a column name or a file extension, so it is\nright even when the database says nothing about what it stores:",[310,412,413,423],{},[313,414,415],{},[316,416,417,420],{},[319,418,419],{},"What is in the blob",[319,421,422],{},"What you get",[326,424,425,433,441,448,456,464],{},[316,426,427,430],{},[331,428,429],{},"PNG, JPEG, GIF, WebP, BMP, ICO, AVIF, SVG",[331,431,432],{},"the picture",[316,434,435,438],{},[331,436,437],{},"MP4, MOV, WebM, Matroska",[331,439,440],{},"a player, with controls",[316,442,443,446],{},[331,444,445],{},"MP3, WAV, Ogg, FLAC",[331,447,440],{},[316,449,450,453],{},[331,451,452],{},"TIFF, HEIC",[331,454,455],{},"the name and size — no browser can display these, so download it instead",[316,457,458,461],{},[331,459,460],{},"text",[331,462,463],{},"the text",[316,465,466,469],{},[331,467,468],{},"anything else",[331,470,471],{},"a hex dump of the first kilobyte",[15,473,474,475,478,479,482,483,486],{},"Right-click a cell for ",[84,476,477],{},"Preview value"," and ",[84,480,481],{},"Download value",". The download carries the detected\nmedia type, so a blob that is a PNG arrives as a ",[33,484,485],{},".png"," file.",[154,488],{"alt":489,"dark":490,"light":491},"The value preview showing a video stored in a SQLite blob, with playback controls","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-blob-video-preview-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-blob-video-preview-light.png",[15,493,494],{},"Two limits are deliberate, and both exist so that a large value cannot make the grid expensive:",[19,496,497,503],{},[22,498,499,502],{},[84,500,501],{},"thumbnails only for images under 512 KB."," A larger image shows its size and opens in full when\nyou ask for the preview;",[22,504,505,508],{},[84,506,507],{},"nothing is decoded while rows render."," The preview builds its object URL when you open it and\nreleases it when you close it.",[15,510,511,512,515,516,519],{},"A blob of zero length reads ",[33,513,514],{},"BLOB · empty",", which is not the same as ",[33,517,518],{},"NULL"," and is not shown as one.",[70,521,523],{"id":522},"exporting-the-result","Exporting the result",[15,525,526,527,530,531,533,534,536],{},"The export button writes the ",[84,528,529],{},"whole result set",", not the page of rows the grid happens to show,\nand it belongs to the tab you are on: on ",[84,532,261],{}," it exports the file you are previewing, on ",[84,535,265],{},"\nthe result of your query.",[154,538],{"alt":539,"dark":540,"light":541},"The export menu offering CSV, JSON and Parquet","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-export-formats-dark.png","\u002Fdocs\u002Fimages\u002Fgenerated\u002Fviewer-export-formats-light.png",[310,543,544,553],{},[313,545,546],{},[316,547,548,550],{},[319,549,321],{},[319,551,552],{},"Formats",[326,554,555,563],{},[316,556,557,560],{},[331,558,559],{},"Parquet, JSON Lines",[331,561,562],{},"CSV, JSON, Parquet — written by DuckDB itself, so types survive the round trip",[316,564,565,567],{},[331,566,349],{},[331,568,569],{},"CSV and JSON",[15,571,572,573,576],{},"Binary values are written as hex in CSV and JSON. To get the bytes themselves, use ",[84,574,575],{},"Download\nvalue"," on the cell.",[70,578,580],{"id":579},"limits","Limits",[19,582,583,608,614,624,630],{},[22,584,585,588,589,478,591,594,595,46,598,46,601,604,605,87],{},[84,586,587],{},"Read-only."," ",[33,590,99],{},[33,592,593],{},"WITH … SELECT"," only — no ",[33,596,597],{},"INSERT",[33,599,600],{},"UPDATE",[33,602,603],{},"CREATE"," or ",[33,606,607],{},"COPY",[22,609,610,613],{},[84,611,612],{},"A file has to exist already."," The viewers open data; they do not generate or edit it.",[22,615,616,619,620,623],{},[84,617,618],{},"10,000 rows per query."," Results are capped, so a ",[33,621,622],{},"SELECT *"," over a huge file stays responsive;\naggregate in SQL rather than scrolling.",[22,625,626,629],{},[84,627,628],{},"One format at a time."," Several Parquet files together, or several JSONL files together — but\nnot Parquet joined to JSONL, and not a file joined to a database.",[22,631,632,635],{},[84,633,634],{},"The browser's memory is the ceiling."," There is no fixed file-size limit; what a tab can hold\ndepends on the machine, the format and the query.",[15,637,638,639,87],{},"Querying across different sources is a DBConvert Streams feature rather than a browser one — see\n",[25,640,642],{"href":641},"\u002Fdocs\u002Fdatabase-explorer\u002Ffederated-queries","Federated queries",[70,644,646],{"id":645},"when-a-file-will-not-open","When a file will not open",[19,648,649,655,661],{},[22,650,651,654],{},[84,652,653],{},"Wrong page for the file."," Each viewer checks the signature and says which of the three pages\nthe file belongs to, rather than failing vaguely. Opening a Parquet file in the JSONL viewer is a\none-click correction.",[22,656,657,660],{},[84,658,659],{},"A JSONL file with malformed lines"," is reported with the count before anything is queried. Other\nfiles already open stay open.",[22,662,663,670],{},[84,664,665,666,669],{},"A SQLite database marked as WAL but without its ",[33,667,668],{},"-wal"," sidecar"," is still a valid, self-contained\nsnapshot when its changes were checkpointed, so it is read as one. That affects only the private\ncopy in the tab; your file is not modified.",[672,673,674],"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":118,"searchDepth":131,"depth":131,"links":676},[677,678,681,682,683,684,685,686,687],{"id":72,"depth":131,"text":73},{"id":103,"depth":131,"text":104,"children":679},[680],{"id":189,"depth":137,"text":190},{"id":254,"depth":131,"text":255},{"id":304,"depth":131,"text":305},{"id":366,"depth":131,"text":367},{"id":382,"depth":131,"text":383},{"id":522,"depth":131,"text":523},{"id":579,"depth":131,"text":580},{"id":645,"depth":131,"text":646},"Reference for the online Parquet, JSON Lines and SQLite viewers — opening several files and querying across them, binary and media values, export, and the limits.","md",{},false,"\u002Fdocs\u002Fonline-viewers",null,{"title":5,"description":688},"docs\u002Fonline-viewers","uLU7FDGO6PaP7XAGLmKop6_yWKG5dAh3kfByQ1NSYoY",1788813428460]