[{"data":1,"prerenderedAt":2060},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Fchange-field-type-pyqgis":3},{"id":4,"title":5,"body":6,"description":2049,"extension":2050,"meta":2051,"navigation":176,"path":2056,"seo":2057,"stem":2058,"__hash__":2059},"docs\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Fchange-field-type-pyqgis\u002Findex.md","Change a Field Type in PyQGIS",{"type":7,"value":8,"toc":2035},"minimark",[9,13,17,26,117,122,135,139,142,359,383,387,390,688,693,697,704,789,1114,1128,1132,1135,1384,1393,1397,1400,1470,1656,1664,1668,1675,1851,1860,1864,1896,1900,1928,1932,1935,1939,1945,1959,1968,1985,1991,1997,2001,2031],[10,11,5],"h1",{"id":12},"change-a-field-type-in-pyqgis",[14,15,16],"p",{},"Numbers stored as text are one of the most common data problems in GIS. A CSV import guessed wrong, a spreadsheet had one cell with \"n\u002Fa\" in a numeric column, a database exported everything as strings. The symptoms are confusing: sorting puts \"100\" before \"20\", graduated styles refuse the field, sums concatenate instead of adding. Dates stored as text cause the same trouble with every time-based tool. Changing the field's type fixes it — but most formats cannot change a column's type in place, and blind conversion silently turns bad values into NULL.",[14,18,19,20,25],{},"This recipe belongs to ",[21,22,24],"a",{"href":23},"\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002F","Attribute Tables & Field Management",". It explains why types are hard to change in place, converts with refactor fields into a new layer, converts in place by adding a new field and copying, finds values that fail to convert before they are lost, and handles dates and number formats.",[14,27,28],{},[29,30,35,39,43,50,59,69,75,81,86,90,95,100,105,108,111,114],"svg",{"viewBox":31,"role":32,"ariaLabel":33,"xmlns":34},"0 0 760 262","img","Text values sorting as 100, 20, 3 and failing to sum, compared with integer values sorting as 3, 20, 100 and summing to 123","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[36,37,38],"title",{},"Why sorting and sums go wrong",[40,41,42],"desc",{},"A field stored as text sorts lexicographically: 100, 20, 3, so 100 comes first. Summing text concatenates or fails. The same values stored as integers sort numerically, 3, 20, 100, and sum to 123. Converting the type fixes both, provided every value can be parsed.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","760","262","#f6f3ea",[51,52,58],"text",{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"380","28","text-anchor:middle;font-size:14px;font-family:sans-serif;font-weight:bold","#17211d","middle","Same digits, different type",[44,60],{"x":61,"y":62,"width":63,"height":64,"rx":65,"fill":66,"stroke":67,"style":68},"24","56","340","190","8","#fdf2e2","#b91c1c","stroke-width:2",[51,70,74],{"x":71,"y":72,"style":73,"fill":67,"textAnchor":57},"194","94.6","text-anchor:middle;font-size:11.0px;font-family:sans-serif;font-weight:bold","text field",[51,76,80],{"x":71,"y":77,"style":78,"fill":79,"textAnchor":57},"124.6","text-anchor:middle;font-size:9.5px;font-family:monospace","#2f3b35","\"100\" \u003C \"20\" \u003C \"3\"",[51,82,85],{"x":71,"y":83,"style":84,"fill":79,"textAnchor":57},"154.6","text-anchor:middle;font-size:10.0px;font-family:sans-serif","sum → error or \"100203\"",[51,87,89],{"x":71,"y":88,"style":84,"fill":79,"textAnchor":57},"184.6","graduated style refuses",[51,91,94],{"x":71,"y":92,"style":84,"fill":93,"textAnchor":57},"214.6","#59645f","lexicographic",[44,96],{"x":97,"y":62,"width":63,"height":64,"rx":65,"fill":98,"stroke":99,"style":68},"396","#e8efe6","#15803d",[51,101,104],{"x":102,"y":72,"style":73,"fill":103,"textAnchor":57},"566","#166534","integer field",[51,106,107],{"x":102,"y":77,"style":78,"fill":79,"textAnchor":57},"3 \u003C 20 \u003C 100",[51,109,110],{"x":102,"y":83,"style":84,"fill":79,"textAnchor":57},"sum → 123",[51,112,113],{"x":102,"y":88,"style":84,"fill":79,"textAnchor":57},"graduated style works",[51,115,116],{"x":102,"y":92,"style":84,"fill":93,"textAnchor":57},"numeric",[118,119,121],"h2",{"id":120},"prerequisites","Prerequisites",[123,124,125,129,132],"ul",{},[126,127,128],"li",{},"QGIS 3.34 LTR or newer, or the QGIS 4 series.",[126,130,131],{},"Write access to the layer, or a place to write a converted copy.",[126,133,134],{},"Knowledge of how values are formatted — decimal comma or point, date order — before converting.",[118,136,138],{"id":137},"understand-why-in-place-type-changes-are-rare","Understand why in-place type changes are rare",[14,140,141],{},"GeoPackage, shapefile and most file formats store a column's type in the table definition; changing it means rewriting the table. QGIS's providers therefore generally do not offer \"change type\" as an edit. Two approaches work everywhere: write a new layer with the converted schema, or add a new field of the right type to the existing layer, copy converted values into it, and remove the old one.",[143,144,149],"pre",{"className":145,"code":146,"language":147,"meta":148,"style":148},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject, QgsVectorDataProvider\n\nlayer = QgsProject.instance().mapLayersByName(\"measurements\")[0]\ncaps = layer.dataProvider().capabilities()\nfor name, flag in ((\"add fields\", QgsVectorDataProvider.AddAttributes),\n                   (\"delete fields\", QgsVectorDataProvider.DeleteAttributes),\n                   (\"rename fields\", QgsVectorDataProvider.RenameAttributes)):\n    print(f\"{name:\u003C14}\", bool(caps & flag))\nfor f in layer.fields():\n    print(f\"{f.name():\u003C16} {f.typeName():\u003C10} {f.type()}\")\n","python","",[150,151,152,171,178,203,214,235,247,258,302,315],"code",{"__ignoreMap":148},[153,154,157,161,165,168],"span",{"class":155,"line":156},"line",1,[153,158,160],{"class":159},"snl16","from",[153,162,164],{"class":163},"s95oV"," qgis.core ",[153,166,167],{"class":159},"import",[153,169,170],{"class":163}," QgsProject, QgsVectorDataProvider\n",[153,172,174],{"class":155,"line":173},2,[153,175,177],{"emptyLinePlaceholder":176},true,"\n",[153,179,181,184,187,190,194,197,200],{"class":155,"line":180},3,[153,182,183],{"class":163},"layer ",[153,185,186],{"class":159},"=",[153,188,189],{"class":163}," QgsProject.instance().mapLayersByName(",[153,191,193],{"class":192},"sU2Wk","\"measurements\"",[153,195,196],{"class":163},")[",[153,198,46],{"class":199},"sDLfK",[153,201,202],{"class":163},"]\n",[153,204,206,209,211],{"class":155,"line":205},4,[153,207,208],{"class":163},"caps ",[153,210,186],{"class":159},[153,212,213],{"class":163}," layer.dataProvider().capabilities()\n",[153,215,217,220,223,226,229,232],{"class":155,"line":216},5,[153,218,219],{"class":159},"for",[153,221,222],{"class":163}," name, flag ",[153,224,225],{"class":159},"in",[153,227,228],{"class":163}," ((",[153,230,231],{"class":192},"\"add fields\"",[153,233,234],{"class":163},", QgsVectorDataProvider.AddAttributes),\n",[153,236,238,241,244],{"class":155,"line":237},6,[153,239,240],{"class":163},"                   (",[153,242,243],{"class":192},"\"delete fields\"",[153,245,246],{"class":163},", QgsVectorDataProvider.DeleteAttributes),\n",[153,248,250,252,255],{"class":155,"line":249},7,[153,251,240],{"class":163},[153,253,254],{"class":192},"\"rename fields\"",[153,256,257],{"class":163},", QgsVectorDataProvider.RenameAttributes)):\n",[153,259,261,264,267,270,273,276,279,282,285,287,290,293,296,299],{"class":155,"line":260},8,[153,262,263],{"class":199},"    print",[153,265,266],{"class":163},"(",[153,268,269],{"class":159},"f",[153,271,272],{"class":192},"\"",[153,274,275],{"class":199},"{",[153,277,278],{"class":163},"name",[153,280,281],{"class":159},":\u003C14",[153,283,284],{"class":199},"}",[153,286,272],{"class":192},[153,288,289],{"class":163},", ",[153,291,292],{"class":199},"bool",[153,294,295],{"class":163},"(caps ",[153,297,298],{"class":159},"&",[153,300,301],{"class":163}," flag))\n",[153,303,305,307,310,312],{"class":155,"line":304},9,[153,306,219],{"class":159},[153,308,309],{"class":163}," f ",[153,311,225],{"class":159},[153,313,314],{"class":163}," layer.fields():\n",[153,316,318,320,322,324,326,328,331,334,336,339,342,345,347,349,352,354,356],{"class":155,"line":317},10,[153,319,263],{"class":199},[153,321,266],{"class":163},[153,323,269],{"class":159},[153,325,272],{"class":192},[153,327,275],{"class":199},[153,329,330],{"class":163},"f.name()",[153,332,333],{"class":159},":\u003C16",[153,335,284],{"class":199},[153,337,338],{"class":199}," {",[153,340,341],{"class":163},"f.typeName()",[153,343,344],{"class":159},":\u003C10",[153,346,284],{"class":199},[153,348,338],{"class":199},[153,350,351],{"class":163},"f.type()",[153,353,284],{"class":199},[153,355,272],{"class":192},[153,357,358],{"class":163},")\n",[14,360,361,365,366,369,370,373,374,377,378,382],{},[362,363,364],"strong",{},"Breakdown:"," The capability flags tell you which route is possible on this provider: adding, deleting and renaming fields together allow the in-place route. Printing each field's provider type name and QGIS type shows which columns are text that should not be — a ",[150,367,368],{},"String"," column called ",[150,371,372],{},"depth_m"," is the usual suspect. PostgreSQL can change types with ",[150,375,376],{},"ALTER TABLE … ALTER COLUMN … TYPE … USING",", which is the best route when the data lives there; see ",[21,379,381],{"href":380},"\u002Fspatial-data-processing-automation\u002Fpostgis-and-database-workflows\u002Fexecute-sql-on-postgis-pyqgis\u002F","executing SQL on PostGIS",".",[118,384,386],{"id":385},"find-values-that-will-not-convert","Find values that will not convert",[14,388,389],{},"Before converting, find the values that cannot be parsed. Conversion turns them into NULL without complaint, and the evidence is gone.",[143,391,393],{"className":145,"code":392,"language":147,"meta":148,"style":148},"import re\n\ndef parses_as_number(text, decimal=\",\"):\n    if text is None:\n        return True\n    t = str(text).strip().replace(\" \", \"\")\n    if decimal == \",\":\n        t = t.replace(\".\", \"\").replace(\",\", \".\")\n    return re.fullmatch(r\"[-+]?\\d+(\\.\\d+)?([eE][-+]?\\d+)?\", t) is not None or t == \"\"\n\nbad = {}\nfor f in layer.getFeatures():\n    v = f[\"depth_m\"]\n    if not parses_as_number(v):\n        bad[f.id()] = v\nprint(len(bad), \"values will not convert:\", list(bad.values())[:10])\n",[150,394,395,402,406,426,443,451,474,489,517,593,597,608,620,636,646,657],{"__ignoreMap":148},[153,396,397,399],{"class":155,"line":156},[153,398,167],{"class":159},[153,400,401],{"class":163}," re\n",[153,403,404],{"class":155,"line":173},[153,405,177],{"emptyLinePlaceholder":176},[153,407,408,411,415,418,420,423],{"class":155,"line":180},[153,409,410],{"class":159},"def",[153,412,414],{"class":413},"svObZ"," parses_as_number",[153,416,417],{"class":163},"(text, decimal",[153,419,186],{"class":159},[153,421,422],{"class":192},"\",\"",[153,424,425],{"class":163},"):\n",[153,427,428,431,434,437,440],{"class":155,"line":205},[153,429,430],{"class":159},"    if",[153,432,433],{"class":163}," text ",[153,435,436],{"class":159},"is",[153,438,439],{"class":199}," None",[153,441,442],{"class":163},":\n",[153,444,445,448],{"class":155,"line":216},[153,446,447],{"class":159},"        return",[153,449,450],{"class":199}," True\n",[153,452,453,456,458,461,464,467,469,472],{"class":155,"line":237},[153,454,455],{"class":163},"    t ",[153,457,186],{"class":159},[153,459,460],{"class":199}," str",[153,462,463],{"class":163},"(text).strip().replace(",[153,465,466],{"class":192},"\" \"",[153,468,289],{"class":163},[153,470,471],{"class":192},"\"\"",[153,473,358],{"class":163},[153,475,476,478,481,484,487],{"class":155,"line":249},[153,477,430],{"class":159},[153,479,480],{"class":163}," decimal ",[153,482,483],{"class":159},"==",[153,485,486],{"class":192}," \",\"",[153,488,442],{"class":163},[153,490,491,494,496,499,502,504,506,509,511,513,515],{"class":155,"line":260},[153,492,493],{"class":163},"        t ",[153,495,186],{"class":159},[153,497,498],{"class":163}," t.replace(",[153,500,501],{"class":192},"\".\"",[153,503,289],{"class":163},[153,505,471],{"class":192},[153,507,508],{"class":163},").replace(",[153,510,422],{"class":192},[153,512,289],{"class":163},[153,514,501],{"class":192},[153,516,358],{"class":163},[153,518,519,522,525,528,530,533,536,539,542,544,548,550,552,555,557,560,562,564,566,568,570,572,575,577,580,582,585,588,590],{"class":155,"line":304},[153,520,521],{"class":159},"    return",[153,523,524],{"class":163}," re.fullmatch(",[153,526,527],{"class":159},"r",[153,529,272],{"class":192},[153,531,532],{"class":199},"[-+]",[153,534,535],{"class":159},"?",[153,537,538],{"class":199},"\\d",[153,540,541],{"class":159},"+",[153,543,266],{"class":199},[153,545,547],{"class":546},"sRjNt","\\.",[153,549,538],{"class":199},[153,551,541],{"class":159},[153,553,554],{"class":199},")",[153,556,535],{"class":159},[153,558,559],{"class":199},"([eE][-+]",[153,561,535],{"class":159},[153,563,538],{"class":199},[153,565,541],{"class":159},[153,567,554],{"class":199},[153,569,535],{"class":159},[153,571,272],{"class":192},[153,573,574],{"class":163},", t) ",[153,576,436],{"class":159},[153,578,579],{"class":159}," not",[153,581,439],{"class":199},[153,583,584],{"class":159}," or",[153,586,587],{"class":163}," t ",[153,589,483],{"class":159},[153,591,592],{"class":192}," \"\"\n",[153,594,595],{"class":155,"line":317},[153,596,177],{"emptyLinePlaceholder":176},[153,598,600,603,605],{"class":155,"line":599},11,[153,601,602],{"class":163},"bad ",[153,604,186],{"class":159},[153,606,607],{"class":163}," {}\n",[153,609,611,613,615,617],{"class":155,"line":610},12,[153,612,219],{"class":159},[153,614,309],{"class":163},[153,616,225],{"class":159},[153,618,619],{"class":163}," layer.getFeatures():\n",[153,621,623,626,628,631,634],{"class":155,"line":622},13,[153,624,625],{"class":163},"    v ",[153,627,186],{"class":159},[153,629,630],{"class":163}," f[",[153,632,633],{"class":192},"\"depth_m\"",[153,635,202],{"class":163},[153,637,639,641,643],{"class":155,"line":638},14,[153,640,430],{"class":159},[153,642,579],{"class":159},[153,644,645],{"class":163}," parses_as_number(v):\n",[153,647,649,652,654],{"class":155,"line":648},15,[153,650,651],{"class":163},"        bad[f.id()] ",[153,653,186],{"class":159},[153,655,656],{"class":163}," v\n",[153,658,660,663,665,668,671,674,676,679,682,685],{"class":155,"line":659},16,[153,661,662],{"class":199},"print",[153,664,266],{"class":163},[153,666,667],{"class":199},"len",[153,669,670],{"class":163},"(bad), ",[153,672,673],{"class":192},"\"values will not convert:\"",[153,675,289],{"class":163},[153,677,678],{"class":199},"list",[153,680,681],{"class":163},"(bad.values())[:",[153,683,684],{"class":199},"10",[153,686,687],{"class":163},"])\n",[14,689,690,692],{},[362,691,364],{}," The test mirrors the conversion you intend to do: here, European formatting where a dot groups thousands and a comma marks decimals. Typical failures are placeholders (\"n\u002Fa\", \"-\", \"unknown\"), units typed into the cell (\"12 m\"), and stray characters. Listing a sample lets you decide per pattern: placeholders become NULL deliberately, units can be stripped, genuine typos go back to whoever owns the data. Empty strings parse as \"no value\" and become NULL.",[118,694,696],{"id":695},"convert-into-a-new-layer-with-refactor-fields","Convert into a new layer with refactor fields",[14,698,699,700,703],{},"When writing a converted copy is acceptable, ",[150,701,702],{},"native:refactorfields"," changes the type and cleans values in one step.",[14,705,706],{},[29,707,710,713,716,719,734,737,742,747,752,757,762,766,770,775,779,782,786],{"viewBox":708,"role":32,"ariaLabel":709,"xmlns":34},"0 0 760 196","A refactor mapping that cleans text with an expression and converts it to a real number, with failures already listed beforehand",[36,711,712],{},"Convert with an expression per field",[40,714,715],{},"Refactor fields defines the output field as a double and fills it with an expression that cleans the text first: replace the decimal comma with a point, strip units and spaces, then convert with to_real. Values that still fail to convert become NULL, which the earlier check has already listed, so nothing is lost silently.",[44,717],{"x":46,"y":46,"width":47,"height":718,"fill":49},"196",[720,721,722],"defs",{},[723,724,730],"marker",{"id":725,"viewBox":726,"refX":65,"refY":727,"markerWidth":728,"markerHeight":728,"orient":729},"ftRefactorArrow","0 0 10 10","5","7","auto-start-reverse",[731,732],"path",{"d":733,"fill":79},"M0 0 L10 5 L0 10 z",[51,735,736],{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"Clean, then convert, in one expression",[44,738],{"x":61,"y":739,"width":740,"height":741,"rx":65,"fill":66,"stroke":67,"style":68},"60","200","120",[51,743,51],{"x":744,"y":745,"style":746,"fill":67,"textAnchor":57},"124","110.78","text-anchor:middle;font-size:11.5px;font-family:sans-serif;font-weight:bold",[51,748,751],{"x":744,"y":749,"style":750,"fill":79,"textAnchor":57},"136.78","text-anchor:middle;font-size:10.0px;font-family:monospace","\"12,5 m\"",[155,753],{"x1":754,"y1":741,"x2":755,"y2":741,"stroke":79,"style":756},"224","266","stroke-width:1.8;marker-end:url(#ftRefactorArrow)",[44,758],{"x":759,"y":739,"width":760,"height":741,"rx":65,"fill":66,"stroke":761,"style":68},"270","220","#b45309",[51,763,765],{"x":53,"y":764,"style":746,"fill":761,"textAnchor":57},"97.78","clean",[51,767,769],{"x":53,"y":768,"style":750,"fill":79,"textAnchor":57},"123.78","replace(…)",[51,771,774],{"x":53,"y":772,"style":773,"fill":93,"textAnchor":57},"149.78","text-anchor:middle;font-size:10.5px;font-family:sans-serif","comma → point",[155,776],{"x1":777,"y1":741,"x2":778,"y2":741,"stroke":79,"style":756},"490","532",[44,780],{"x":781,"y":739,"width":740,"height":741,"rx":65,"fill":98,"stroke":99,"style":68},"536",[51,783,785],{"x":784,"y":745,"style":746,"fill":103,"textAnchor":57},"636","double",[51,787,788],{"x":784,"y":749,"style":750,"fill":79,"textAnchor":57},"12.5",[143,790,792],{"className":145,"code":791,"language":147,"meta":148,"style":148},"import processing\nfrom qgis.PyQt.QtCore import QVariant\n\nclean_expr = \"\"\"to_real(\n    replace(replace(regexp_replace(trim(\"depth_m\"), '[^0-9,.-]', ''), '.', ''), ',', '.')\n)\"\"\"\nmapping = []\nfor f in layer.fields():\n    if f.name() == \"depth_m\":\n        mapping.append({\"name\": \"depth_m\", \"type\": QVariant.Double, \"length\": 10,\n                        \"precision\": 2, \"expression\": clean_expr})\n    else:\n        mapping.append({\"name\": f.name(), \"type\": f.type(), \"length\": f.length(),\n                        \"precision\": f.precision(), \"expression\": f'\"{f.name()}\"'})\n\nconverted = processing.run(\"native:refactorfields\", {\n    \"INPUT\": layer, \"FIELDS_MAPPING\": mapping, \"OUTPUT\": \"memory:measurements_typed\"})[\"OUTPUT\"]\nnulls = sum(1 for f in converted.getFeatures() if f[\"depth_m\"] is None\n            or (hasattr(f[\"depth_m\"], \"isNull\") and f[\"depth_m\"].isNull()))\nprint(nulls, \"NULL depths after conversion\")\n",[150,793,794,801,813,817,827,832,837,847,857,871,902,920,927,946,974,978,994,1024,1065,1101],{"__ignoreMap":148},[153,795,796,798],{"class":155,"line":156},[153,797,167],{"class":159},[153,799,800],{"class":163}," processing\n",[153,802,803,805,808,810],{"class":155,"line":173},[153,804,160],{"class":159},[153,806,807],{"class":163}," qgis.PyQt.QtCore ",[153,809,167],{"class":159},[153,811,812],{"class":163}," QVariant\n",[153,814,815],{"class":155,"line":180},[153,816,177],{"emptyLinePlaceholder":176},[153,818,819,822,824],{"class":155,"line":205},[153,820,821],{"class":163},"clean_expr ",[153,823,186],{"class":159},[153,825,826],{"class":192}," \"\"\"to_real(\n",[153,828,829],{"class":155,"line":216},[153,830,831],{"class":192},"    replace(replace(regexp_replace(trim(\"depth_m\"), '[^0-9,.-]', ''), '.', ''), ',', '.')\n",[153,833,834],{"class":155,"line":237},[153,835,836],{"class":192},")\"\"\"\n",[153,838,839,842,844],{"class":155,"line":249},[153,840,841],{"class":163},"mapping ",[153,843,186],{"class":159},[153,845,846],{"class":163}," []\n",[153,848,849,851,853,855],{"class":155,"line":260},[153,850,219],{"class":159},[153,852,309],{"class":163},[153,854,225],{"class":159},[153,856,314],{"class":163},[153,858,859,861,864,866,869],{"class":155,"line":304},[153,860,430],{"class":159},[153,862,863],{"class":163}," f.name() ",[153,865,483],{"class":159},[153,867,868],{"class":192}," \"depth_m\"",[153,870,442],{"class":163},[153,872,873,876,879,882,884,886,889,892,895,897,899],{"class":155,"line":317},[153,874,875],{"class":163},"        mapping.append({",[153,877,878],{"class":192},"\"name\"",[153,880,881],{"class":163},": ",[153,883,633],{"class":192},[153,885,289],{"class":163},[153,887,888],{"class":192},"\"type\"",[153,890,891],{"class":163},": QVariant.Double, ",[153,893,894],{"class":192},"\"length\"",[153,896,881],{"class":163},[153,898,684],{"class":199},[153,900,901],{"class":163},",\n",[153,903,904,907,909,912,914,917],{"class":155,"line":599},[153,905,906],{"class":192},"                        \"precision\"",[153,908,881],{"class":163},[153,910,911],{"class":199},"2",[153,913,289],{"class":163},[153,915,916],{"class":192},"\"expression\"",[153,918,919],{"class":163},": clean_expr})\n",[153,921,922,925],{"class":155,"line":610},[153,923,924],{"class":159},"    else",[153,926,442],{"class":163},[153,928,929,931,933,936,938,941,943],{"class":155,"line":622},[153,930,875],{"class":163},[153,932,878],{"class":192},[153,934,935],{"class":163},": f.name(), ",[153,937,888],{"class":192},[153,939,940],{"class":163},": f.type(), ",[153,942,894],{"class":192},[153,944,945],{"class":163},": f.length(),\n",[153,947,948,950,953,955,957,959,962,964,966,968,971],{"class":155,"line":638},[153,949,906],{"class":192},[153,951,952],{"class":163},": f.precision(), ",[153,954,916],{"class":192},[153,956,881],{"class":163},[153,958,269],{"class":159},[153,960,961],{"class":192},"'\"",[153,963,275],{"class":199},[153,965,330],{"class":163},[153,967,284],{"class":199},[153,969,970],{"class":192},"\"'",[153,972,973],{"class":163},"})\n",[153,975,976],{"class":155,"line":648},[153,977,177],{"emptyLinePlaceholder":176},[153,979,980,983,985,988,991],{"class":155,"line":659},[153,981,982],{"class":163},"converted ",[153,984,186],{"class":159},[153,986,987],{"class":163}," processing.run(",[153,989,990],{"class":192},"\"native:refactorfields\"",[153,992,993],{"class":163},", {\n",[153,995,997,1000,1003,1006,1009,1012,1014,1017,1020,1022],{"class":155,"line":996},17,[153,998,999],{"class":192},"    \"INPUT\"",[153,1001,1002],{"class":163},": layer, ",[153,1004,1005],{"class":192},"\"FIELDS_MAPPING\"",[153,1007,1008],{"class":163},": mapping, ",[153,1010,1011],{"class":192},"\"OUTPUT\"",[153,1013,881],{"class":163},[153,1015,1016],{"class":192},"\"memory:measurements_typed\"",[153,1018,1019],{"class":163},"})[",[153,1021,1011],{"class":192},[153,1023,202],{"class":163},[153,1025,1027,1030,1032,1035,1037,1040,1043,1045,1047,1050,1053,1055,1057,1060,1062],{"class":155,"line":1026},18,[153,1028,1029],{"class":163},"nulls ",[153,1031,186],{"class":159},[153,1033,1034],{"class":199}," sum",[153,1036,266],{"class":163},[153,1038,1039],{"class":199},"1",[153,1041,1042],{"class":159}," for",[153,1044,309],{"class":163},[153,1046,225],{"class":159},[153,1048,1049],{"class":163}," converted.getFeatures() ",[153,1051,1052],{"class":159},"if",[153,1054,630],{"class":163},[153,1056,633],{"class":192},[153,1058,1059],{"class":163},"] ",[153,1061,436],{"class":159},[153,1063,1064],{"class":199}," None\n",[153,1066,1068,1071,1074,1077,1080,1082,1085,1088,1091,1094,1096,1098],{"class":155,"line":1067},19,[153,1069,1070],{"class":159},"            or",[153,1072,1073],{"class":163}," (",[153,1075,1076],{"class":199},"hasattr",[153,1078,1079],{"class":163},"(f[",[153,1081,633],{"class":192},[153,1083,1084],{"class":163},"], ",[153,1086,1087],{"class":192},"\"isNull\"",[153,1089,1090],{"class":163},") ",[153,1092,1093],{"class":159},"and",[153,1095,630],{"class":163},[153,1097,633],{"class":192},[153,1099,1100],{"class":163},"].isNull()))\n",[153,1102,1104,1106,1109,1112],{"class":155,"line":1103},20,[153,1105,662],{"class":199},[153,1107,1108],{"class":163},"(nulls, ",[153,1110,1111],{"class":192},"\"NULL depths after conversion\"",[153,1113,358],{"class":163},[14,1115,1116,1118,1119,1122,1123,1127],{},[362,1117,364],{}," The expression strips anything that is not a digit, comma, dot or minus sign, removes thousands separators, turns the decimal comma into a point and converts with ",[150,1120,1121],{},"to_real",". Every other field is copied unchanged, so the output differs from the input only in the one column. The NULL count afterwards should equal the original NULLs plus the values flagged in the check — if it is higher, the cleaning expression and the check disagree. ",[21,1124,1126],{"href":1125},"\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Frename-and-reorder-fields-pyqgis\u002F","Renaming and reordering fields"," explains the mapping format in more detail.",[118,1129,1131],{"id":1130},"convert-in-place-with-a-new-field","Convert in place with a new field",[14,1133,1134],{},"To keep the same table — its id, relations, styles and forms — add a typed field, fill it from the old one, then swap names.",[143,1136,1138],{"className":145,"code":1137,"language":147,"meta":148,"style":148},"from qgis.core import QgsField, edit\n\ndef to_float(v):\n    if v is None or (hasattr(v, \"isNull\") and v.isNull()):\n        return None\n    t = re.sub(r\"[^0-9,.-]\", \"\", str(v)).replace(\".\", \"\").replace(\",\", \".\")\n    try:\n        return float(t) if t else None\n    except ValueError:\n        return None\n\nwith edit(layer):\n    layer.addAttribute(QgsField(\"depth_m_num\", QVariant.Double, len=10, prec=2))\n    layer.updateFields()\n    new_idx = layer.fields().indexOf(\"depth_m_num\")\n    old_idx = layer.fields().indexOf(\"depth_m\")\n    for f in layer.getFeatures():\n        layer.changeAttributeValue(f.id(), new_idx, to_float(f[old_idx]))\n",[150,1139,1140,1151,1155,1165,1194,1200,1252,1259,1278,1288,1294,1298,1306,1336,1341,1355,1368,1379],{"__ignoreMap":148},[153,1141,1142,1144,1146,1148],{"class":155,"line":156},[153,1143,160],{"class":159},[153,1145,164],{"class":163},[153,1147,167],{"class":159},[153,1149,1150],{"class":163}," QgsField, edit\n",[153,1152,1153],{"class":155,"line":173},[153,1154,177],{"emptyLinePlaceholder":176},[153,1156,1157,1159,1162],{"class":155,"line":180},[153,1158,410],{"class":159},[153,1160,1161],{"class":413}," to_float",[153,1163,1164],{"class":163},"(v):\n",[153,1166,1167,1169,1172,1174,1176,1178,1180,1182,1185,1187,1189,1191],{"class":155,"line":205},[153,1168,430],{"class":159},[153,1170,1171],{"class":163}," v ",[153,1173,436],{"class":159},[153,1175,439],{"class":199},[153,1177,584],{"class":159},[153,1179,1073],{"class":163},[153,1181,1076],{"class":199},[153,1183,1184],{"class":163},"(v, ",[153,1186,1087],{"class":192},[153,1188,1090],{"class":163},[153,1190,1093],{"class":159},[153,1192,1193],{"class":163}," v.isNull()):\n",[153,1195,1196,1198],{"class":155,"line":216},[153,1197,447],{"class":159},[153,1199,1064],{"class":199},[153,1201,1202,1204,1206,1209,1211,1213,1216,1219,1222,1224,1226,1228,1230,1233,1236,1238,1240,1242,1244,1246,1248,1250],{"class":155,"line":237},[153,1203,455],{"class":163},[153,1205,186],{"class":159},[153,1207,1208],{"class":163}," re.sub(",[153,1210,527],{"class":159},[153,1212,272],{"class":192},[153,1214,1215],{"class":199},"[",[153,1217,1218],{"class":159},"^",[153,1220,1221],{"class":199},"0-9,.-]",[153,1223,272],{"class":192},[153,1225,289],{"class":163},[153,1227,471],{"class":192},[153,1229,289],{"class":163},[153,1231,1232],{"class":199},"str",[153,1234,1235],{"class":163},"(v)).replace(",[153,1237,501],{"class":192},[153,1239,289],{"class":163},[153,1241,471],{"class":192},[153,1243,508],{"class":163},[153,1245,422],{"class":192},[153,1247,289],{"class":163},[153,1249,501],{"class":192},[153,1251,358],{"class":163},[153,1253,1254,1257],{"class":155,"line":249},[153,1255,1256],{"class":159},"    try",[153,1258,442],{"class":163},[153,1260,1261,1263,1266,1269,1271,1273,1276],{"class":155,"line":260},[153,1262,447],{"class":159},[153,1264,1265],{"class":199}," float",[153,1267,1268],{"class":163},"(t) ",[153,1270,1052],{"class":159},[153,1272,587],{"class":163},[153,1274,1275],{"class":159},"else",[153,1277,1064],{"class":199},[153,1279,1280,1283,1286],{"class":155,"line":304},[153,1281,1282],{"class":159},"    except",[153,1284,1285],{"class":199}," ValueError",[153,1287,442],{"class":163},[153,1289,1290,1292],{"class":155,"line":317},[153,1291,447],{"class":159},[153,1293,1064],{"class":199},[153,1295,1296],{"class":155,"line":599},[153,1297,177],{"emptyLinePlaceholder":176},[153,1299,1300,1303],{"class":155,"line":610},[153,1301,1302],{"class":159},"with",[153,1304,1305],{"class":163}," edit(layer):\n",[153,1307,1308,1311,1314,1317,1320,1322,1324,1326,1329,1331,1333],{"class":155,"line":622},[153,1309,1310],{"class":163},"    layer.addAttribute(QgsField(",[153,1312,1313],{"class":192},"\"depth_m_num\"",[153,1315,1316],{"class":163},", QVariant.Double, ",[153,1318,667],{"class":1319},"s9osk",[153,1321,186],{"class":159},[153,1323,684],{"class":199},[153,1325,289],{"class":163},[153,1327,1328],{"class":1319},"prec",[153,1330,186],{"class":159},[153,1332,911],{"class":199},[153,1334,1335],{"class":163},"))\n",[153,1337,1338],{"class":155,"line":638},[153,1339,1340],{"class":163},"    layer.updateFields()\n",[153,1342,1343,1346,1348,1351,1353],{"class":155,"line":648},[153,1344,1345],{"class":163},"    new_idx ",[153,1347,186],{"class":159},[153,1349,1350],{"class":163}," layer.fields().indexOf(",[153,1352,1313],{"class":192},[153,1354,358],{"class":163},[153,1356,1357,1360,1362,1364,1366],{"class":155,"line":659},[153,1358,1359],{"class":163},"    old_idx ",[153,1361,186],{"class":159},[153,1363,1350],{"class":163},[153,1365,633],{"class":192},[153,1367,358],{"class":163},[153,1369,1370,1373,1375,1377],{"class":155,"line":996},[153,1371,1372],{"class":159},"    for",[153,1374,309],{"class":163},[153,1376,225],{"class":159},[153,1378,619],{"class":163},[153,1380,1381],{"class":155,"line":1026},[153,1382,1383],{"class":163},"        layer.changeAttributeValue(f.id(), new_idx, to_float(f[old_idx]))\n",[14,1385,1386,1388,1389,1392],{},[362,1387,364],{}," Adding the field inside the edit session and calling ",[150,1390,1391],{},"updateFields"," makes it available immediately. The Python converter applies the same rules as the expression, so the earlier check describes its failures exactly. At this stage both columns exist side by side, which is the moment to verify before removing anything. Doing the copy through the edit buffer means a failure rolls everything back.",[118,1394,1396],{"id":1395},"verify-then-swap","Verify, then swap",[14,1398,1399],{},"Compare old and new values for a sample and summarise before dropping the text column. Once it is gone, so is the evidence of what the raw values were.",[14,1401,1402],{},[29,1403,1405,1408,1411,1413,1420,1423,1427,1431,1434,1439,1442,1446,1449,1452,1456,1460,1464,1467],{"viewBox":708,"role":32,"ariaLabel":1404,"xmlns":34},"A verification step comparing old text and new numeric columns before the text column is deleted and the new column renamed",[36,1406,1407],{},"Verify before swapping",[40,1409,1410],{},"With both columns present, check that every non-empty text value either converted or appears in the known failure list, compare a sample side by side, and check that numeric statistics are plausible. Only then delete the text column and rename the new one to the original name, so expressions and styles keep working.",[44,1412],{"x":46,"y":46,"width":47,"height":718,"fill":49},[720,1414,1415],{},[723,1416,1418],{"id":1417,"viewBox":726,"refX":65,"refY":727,"markerWidth":728,"markerHeight":728,"orient":729},"ftSwapArrow",[731,1419],{"d":733,"fill":79},[51,1421,1422],{"x":53,"y":54,"style":55,"fill":56,"textAnchor":57},"Two columns until you are sure",[44,1424],{"x":61,"y":739,"width":1425,"height":741,"rx":65,"fill":1426,"stroke":93,"style":68},"222","#fffdf7",[51,1428,1430],{"x":1429,"y":745,"style":746,"fill":56,"textAnchor":57},"135","both columns",[51,1432,1433],{"x":1429,"y":749,"style":773,"fill":93,"textAnchor":57},"text + number",[155,1435],{"x1":1436,"y1":741,"x2":1437,"y2":741,"stroke":79,"style":1438},"246","288","stroke-width:1.8;marker-end:url(#ftSwapArrow)",[44,1440],{"x":1441,"y":739,"width":740,"height":741,"rx":65,"fill":66,"stroke":761,"style":68},"292",[51,1443,1445],{"x":1444,"y":764,"style":746,"fill":761,"textAnchor":57},"392","verify",[51,1447,1448],{"x":1444,"y":768,"style":773,"fill":93,"textAnchor":57},"sample, stats",[51,1450,1451],{"x":1444,"y":772,"style":773,"fill":93,"textAnchor":57},"failures known",[155,1453],{"x1":1454,"y1":741,"x2":1455,"y2":741,"stroke":79,"style":1438},"492","534",[44,1457],{"x":1458,"y":739,"width":1459,"height":741,"rx":65,"fill":98,"stroke":99,"style":68},"538","198",[51,1461,1463],{"x":1462,"y":764,"style":746,"fill":103,"textAnchor":57},"637","swap",[51,1465,1466],{"x":1462,"y":768,"style":773,"fill":93,"textAnchor":57},"drop text",[51,1468,1469],{"x":1462,"y":772,"style":773,"fill":93,"textAnchor":57},"rename number",[143,1471,1473],{"className":145,"code":1472,"language":147,"meta":148,"style":148},"vals = [f[\"depth_m_num\"] for f in layer.getFeatures() if f[\"depth_m_num\"] is not None]\nprint(f\"min {min(vals):.2f}  max {max(vals):.2f}  n={len(vals)}\")\nfor f in list(layer.getFeatures())[:5]:\n    print(repr(f[\"depth_m\"]), \"→\", f[\"depth_m_num\"])\n\nwith edit(layer):\n    layer.deleteAttribute(layer.fields().indexOf(\"depth_m\"))\n    layer.updateFields()\n    layer.renameAttribute(layer.fields().indexOf(\"depth_m_num\"), \"depth_m\")\nprint(layer.fields().field(\"depth_m\").typeName())\n",[150,1474,1475,1514,1562,1581,1607,1611,1617,1626,1630,1644],{"__ignoreMap":148},[153,1476,1477,1480,1482,1485,1487,1489,1491,1493,1495,1498,1500,1502,1504,1506,1508,1510,1512],{"class":155,"line":156},[153,1478,1479],{"class":163},"vals ",[153,1481,186],{"class":159},[153,1483,1484],{"class":163}," [f[",[153,1486,1313],{"class":192},[153,1488,1059],{"class":163},[153,1490,219],{"class":159},[153,1492,309],{"class":163},[153,1494,225],{"class":159},[153,1496,1497],{"class":163}," layer.getFeatures() ",[153,1499,1052],{"class":159},[153,1501,630],{"class":163},[153,1503,1313],{"class":192},[153,1505,1059],{"class":163},[153,1507,436],{"class":159},[153,1509,579],{"class":159},[153,1511,439],{"class":199},[153,1513,202],{"class":163},[153,1515,1516,1518,1520,1522,1525,1528,1531,1534,1536,1539,1542,1544,1546,1548,1551,1554,1556,1558,1560],{"class":155,"line":173},[153,1517,662],{"class":199},[153,1519,266],{"class":163},[153,1521,269],{"class":159},[153,1523,1524],{"class":192},"\"min ",[153,1526,1527],{"class":199},"{min",[153,1529,1530],{"class":163},"(vals)",[153,1532,1533],{"class":159},":.2f",[153,1535,284],{"class":199},[153,1537,1538],{"class":192},"  max ",[153,1540,1541],{"class":199},"{max",[153,1543,1530],{"class":163},[153,1545,1533],{"class":159},[153,1547,284],{"class":199},[153,1549,1550],{"class":192},"  n=",[153,1552,1553],{"class":199},"{len",[153,1555,1530],{"class":163},[153,1557,284],{"class":199},[153,1559,272],{"class":192},[153,1561,358],{"class":163},[153,1563,1564,1566,1568,1570,1573,1576,1578],{"class":155,"line":180},[153,1565,219],{"class":159},[153,1567,309],{"class":163},[153,1569,225],{"class":159},[153,1571,1572],{"class":199}," list",[153,1574,1575],{"class":163},"(layer.getFeatures())[:",[153,1577,727],{"class":199},[153,1579,1580],{"class":163},"]:\n",[153,1582,1583,1585,1587,1590,1592,1594,1597,1600,1603,1605],{"class":155,"line":205},[153,1584,263],{"class":199},[153,1586,266],{"class":163},[153,1588,1589],{"class":199},"repr",[153,1591,1079],{"class":163},[153,1593,633],{"class":192},[153,1595,1596],{"class":163},"]), ",[153,1598,1599],{"class":192},"\"→\"",[153,1601,1602],{"class":163},", f[",[153,1604,1313],{"class":192},[153,1606,687],{"class":163},[153,1608,1609],{"class":155,"line":216},[153,1610,177],{"emptyLinePlaceholder":176},[153,1612,1613,1615],{"class":155,"line":237},[153,1614,1302],{"class":159},[153,1616,1305],{"class":163},[153,1618,1619,1622,1624],{"class":155,"line":249},[153,1620,1621],{"class":163},"    layer.deleteAttribute(layer.fields().indexOf(",[153,1623,633],{"class":192},[153,1625,1335],{"class":163},[153,1627,1628],{"class":155,"line":260},[153,1629,1340],{"class":163},[153,1631,1632,1635,1637,1640,1642],{"class":155,"line":304},[153,1633,1634],{"class":163},"    layer.renameAttribute(layer.fields().indexOf(",[153,1636,1313],{"class":192},[153,1638,1639],{"class":163},"), ",[153,1641,633],{"class":192},[153,1643,358],{"class":163},[153,1645,1646,1648,1651,1653],{"class":155,"line":317},[153,1647,662],{"class":199},[153,1649,1650],{"class":163},"(layer.fields().field(",[153,1652,633],{"class":192},[153,1654,1655],{"class":163},").typeName())\n",[14,1657,1658,1660,1661,1663],{},[362,1659,364],{}," Plausible minimum and maximum values catch systematic errors such as a decimal separator handled the wrong way, which turns 12,5 into 125. The side-by-side sample shows the conversion on real values. Renaming the new column to the original name keeps expressions, labels and styles that refer to ",[150,1662,372],{}," working — they now see a number. Keep the list of failed values in a log; it is often the most useful output for whoever maintains the data.",[118,1665,1667],{"id":1666},"convert-text-to-dates","Convert text to dates",[14,1669,1670,1671,1674],{},"Dates stored as text need the same care, with the added problem of ordering: ",[150,1672,1673],{},"03\u002F04\u002F2026"," is March or April depending on country.",[143,1676,1678],{"className":145,"code":1677,"language":147,"meta":148,"style":148},"date_expr = \"\"\"CASE\n    WHEN regexp_match(\"visited\", '^\\\\\\\\d{4}-\\\\\\\\d{2}-\\\\\\\\d{2}$') THEN to_date(\"visited\")\n    WHEN regexp_match(\"visited\", '^\\\\\\\\d{2}\\\\\\\\.\\\\\\\\d{2}\\\\\\\\.\\\\\\\\d{4}$') THEN to_date(\"visited\", 'dd.MM.yyyy')\n    WHEN regexp_match(\"visited\", '^\\\\\\\\d{2}\u002F\\\\\\\\d{2}\u002F\\\\\\\\d{4}$') THEN to_date(\"visited\", 'dd\u002FMM\u002Fyyyy')\n    ELSE NULL END\"\"\"\ndated = processing.run(\"native:fieldcalculator\", {\n    \"INPUT\": layer, \"FIELD_NAME\": \"visited_date\", \"FIELD_TYPE\": 3,\n    \"FORMULA\": date_expr, \"OUTPUT\": \"memory:\"})[\"OUTPUT\"]\n",[150,1679,1680,1690,1725,1755,1785,1790,1804,1830],{"__ignoreMap":148},[153,1681,1682,1685,1687],{"class":155,"line":156},[153,1683,1684],{"class":163},"date_expr ",[153,1686,186],{"class":159},[153,1688,1689],{"class":192}," \"\"\"CASE\n",[153,1691,1692,1695,1698,1701,1704,1707,1709,1711,1714,1716,1718,1720,1722],{"class":155,"line":173},[153,1693,1694],{"class":192},"    WHEN regexp_match(\"visited\", '^",[153,1696,1697],{"class":199},"\\\\\\\\",[153,1699,1700],{"class":192},"d",[153,1702,1703],{"class":199},"{4}",[153,1705,1706],{"class":192},"-",[153,1708,1697],{"class":199},[153,1710,1700],{"class":192},[153,1712,1713],{"class":199},"{2}",[153,1715,1706],{"class":192},[153,1717,1697],{"class":199},[153,1719,1700],{"class":192},[153,1721,1713],{"class":199},[153,1723,1724],{"class":192},"$') THEN to_date(\"visited\")\n",[153,1726,1727,1729,1731,1733,1736,1738,1740,1742,1744,1746,1748,1750,1752],{"class":155,"line":180},[153,1728,1694],{"class":192},[153,1730,1697],{"class":199},[153,1732,1700],{"class":192},[153,1734,1735],{"class":199},"{2}\\\\\\\\",[153,1737,382],{"class":192},[153,1739,1697],{"class":199},[153,1741,1700],{"class":192},[153,1743,1735],{"class":199},[153,1745,382],{"class":192},[153,1747,1697],{"class":199},[153,1749,1700],{"class":192},[153,1751,1703],{"class":199},[153,1753,1754],{"class":192},"$') THEN to_date(\"visited\", 'dd.MM.yyyy')\n",[153,1756,1757,1759,1761,1763,1765,1768,1770,1772,1774,1776,1778,1780,1782],{"class":155,"line":205},[153,1758,1694],{"class":192},[153,1760,1697],{"class":199},[153,1762,1700],{"class":192},[153,1764,1713],{"class":199},[153,1766,1767],{"class":192},"\u002F",[153,1769,1697],{"class":199},[153,1771,1700],{"class":192},[153,1773,1713],{"class":199},[153,1775,1767],{"class":192},[153,1777,1697],{"class":199},[153,1779,1700],{"class":192},[153,1781,1703],{"class":199},[153,1783,1784],{"class":192},"$') THEN to_date(\"visited\", 'dd\u002FMM\u002Fyyyy')\n",[153,1786,1787],{"class":155,"line":216},[153,1788,1789],{"class":192},"    ELSE NULL END\"\"\"\n",[153,1791,1792,1795,1797,1799,1802],{"class":155,"line":237},[153,1793,1794],{"class":163},"dated ",[153,1796,186],{"class":159},[153,1798,987],{"class":163},[153,1800,1801],{"class":192},"\"native:fieldcalculator\"",[153,1803,993],{"class":163},[153,1805,1806,1808,1810,1813,1815,1818,1820,1823,1825,1828],{"class":155,"line":249},[153,1807,999],{"class":192},[153,1809,1002],{"class":163},[153,1811,1812],{"class":192},"\"FIELD_NAME\"",[153,1814,881],{"class":163},[153,1816,1817],{"class":192},"\"visited_date\"",[153,1819,289],{"class":163},[153,1821,1822],{"class":192},"\"FIELD_TYPE\"",[153,1824,881],{"class":163},[153,1826,1827],{"class":199},"3",[153,1829,901],{"class":163},[153,1831,1832,1835,1838,1840,1842,1845,1847,1849],{"class":155,"line":260},[153,1833,1834],{"class":192},"    \"FORMULA\"",[153,1836,1837],{"class":163},": date_expr, ",[153,1839,1011],{"class":192},[153,1841,881],{"class":163},[153,1843,1844],{"class":192},"\"memory:\"",[153,1846,1019],{"class":163},[153,1848,1011],{"class":192},[153,1850,202],{"class":163},[14,1852,1853,1855,1856,1859],{},[362,1854,364],{}," Matching each known pattern explicitly and parsing it with its own format string avoids ambiguity; anything that matches no pattern becomes NULL and should appear in a failure list first, as with numbers. The format string follows Qt's date notation — ",[150,1857,1858],{},"dd.MM.yyyy"," for 03.04.2026 as 3 April. Decide the day\u002Fmonth order from the data's origin, not by guessing per value. Field type 3 in the field calculator is date.",[118,1861,1863],{"id":1862},"qgis-version-compatibility","QGIS version compatibility",[14,1865,1866,289,1868,289,1871,1874,1875,1878,1879,289,1881,1884,1885,1888,1889,1892,1893,382],{},[150,1867,702],{},[150,1869,1870],{},"addAttribute",[150,1872,1873],{},"deleteAttribute"," and ",[150,1876,1877],{},"renameAttribute"," work on QGIS 3.34 LTR, 3.40 LTR and QGIS 4. Expression functions ",[150,1880,1121],{},[150,1882,1883],{},"to_date"," with a format argument and ",[150,1886,1887],{},"regexp_match"," are available on all. On QGIS 4, field types are ",[150,1890,1891],{},"QMetaType.Type"," values and provider capabilities use ",[150,1894,1895],{},"Qgis.VectorProviderCapability",[118,1897,1899],{"id":1898},"troubleshooting","Troubleshooting",[123,1901,1902,1908,1914,1920],{},[126,1903,1904,1907],{},[362,1905,1906],{},"Converted values are 100 times too large."," The decimal separator was misread; check the cleaning order.",[126,1909,1910,1913],{},[362,1911,1912],{},"Many values became NULL."," A placeholder or unit was not handled; run the check first.",[126,1915,1916,1919],{},[362,1917,1918],{},"Styles broke after the swap."," The new field was not renamed to the old name.",[126,1921,1922,1927],{},[362,1923,1924,1926],{},[150,1925,1873],{}," fails."," The provider cannot delete fields; use the refactor route.",[118,1929,1931],{"id":1930},"conclusion","Conclusion",[14,1933,1934],{},"Find unconvertible values before converting, convert into a new layer with an expression per field or in place with a new field, keep both columns until you have verified samples and statistics, then delete the text column and give the new one the original name; handle dates with explicit formats per pattern.",[118,1936,1938],{"id":1937},"frequently-asked-questions","Frequently Asked Questions",[14,1940,1941,1944],{},[362,1942,1943],{},"Can I change a field type in a shapefile?","\nNot in place. Write a converted copy, preferably to GeoPackage.",[14,1946,1947,1954,1955,1958],{},[362,1948,1949,1950,1953],{},"Why does ",[150,1951,1952],{},"to_int"," truncate decimals?","\nIt converts to integer by truncation; use ",[150,1956,1957],{},"round()"," first if you need rounding.",[14,1960,1961,1964,1967],{},[362,1962,1963],{},"How do I convert numbers to text with leading zeros?",[150,1965,1966],{},"lpad(to_string(\"code\"), 5, '0')"," turns 42 into \"00042\".",[14,1969,1970,1973,1974,1976,1977,1980,1981,1984],{},[362,1971,1972],{},"Why are the backslashes doubled in the date expression?","\nThe regular expression ",[150,1975,538],{}," must reach QGIS as ",[150,1978,1979],{},"\\\\d"," inside an expression string literal, and Python needs each of those backslashes escaped again in a normal string. Using a raw Python string (",[150,1982,1983],{},"r\"\"\"...\"\"\"",") halves the count and is easier to read.",[14,1986,1987,1990],{},[362,1988,1989],{},"Can I convert a whole table's text columns at once?","\nYes — loop over the fields, test each text column with the parse check, and add a converted mapping entry only for columns where every non-empty value parses. Review the list before running it.",[14,1992,1993,1996],{},[362,1994,1995],{},"Will converting break joins?","\nJoins on a field require matching types on both sides; convert both, or join on an expression.",[118,1998,2000],{"id":1999},"related","Related",[123,2002,2003,2008,2013,2019,2025],{},[126,2004,2005,2007],{},[21,2006,24],{"href":23}," — the guide this recipe belongs to",[126,2009,2010],{},[21,2011,2012],{"href":1125},"Rename and Reorder Fields in PyQGIS",[126,2014,2015],{},[21,2016,2018],{"href":2017},"\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Fadd-field-to-layer-pyqgis\u002F","Add a Field to a Layer in PyQGIS",[126,2020,2021],{},[21,2022,2024],{"href":2023},"\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Fload-csv-as-point-layer-pyqgis\u002F","Load a CSV as a Point Layer in PyQGIS",[126,2026,2027],{},[21,2028,2030],{"href":2029},"\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fhandle-null-values-and-qvariant-pyqgis\u002F","Handle NULL Values and QVariant in PyQGIS",[2032,2033,2034],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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 pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sRjNt, html code.shiki .sRjNt{--shiki-default:#85E89D;--shiki-default-font-weight:bold}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":148,"searchDepth":173,"depth":173,"links":2036},[2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048],{"id":120,"depth":173,"text":121},{"id":137,"depth":173,"text":138},{"id":385,"depth":173,"text":386},{"id":695,"depth":173,"text":696},{"id":1130,"depth":173,"text":1131},{"id":1395,"depth":173,"text":1396},{"id":1666,"depth":173,"text":1667},{"id":1862,"depth":173,"text":1863},{"id":1898,"depth":173,"text":1899},{"id":1930,"depth":173,"text":1931},{"id":1937,"depth":173,"text":1938},{"id":1999,"depth":173,"text":2000},"Convert a field from text to number, number to text, or text to date in PyQGIS — why most formats cannot change a column's type in place, converting with refactor fields or a new field plus copy, catching values that fail to convert, and verifying the result before dropping the original.","md",{"slug":2052,"type":2053,"breadcrumb":2054,"datePublished":2055,"dateModified":2055},"change-field-type-pyqgis","article","Change a Field Type","2026-10-02","\u002Fspatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Fchange-field-type-pyqgis",{"title":5,"description":2049},"spatial-data-processing-automation\u002Fattribute-tables-and-field-management\u002Fchange-field-type-pyqgis\u002Findex","ockNISy7LeNiL8VTJbC3Ti43OB94I2w7DkxwdLjIUl8",1790966260106]