1+ # PowerShell script to generate a SQL CREATE TABLE statement from an Excel file
2+ Write-Host " === GENERATE CREATE TABLE FROM EXCEL ==="
3+
4+ # --- XLSX File Selection ---
5+ $scriptDir = $PSScriptRoot
6+ $excelFiles = Get-ChildItem - Path $scriptDir - Filter * .xlsx
7+
8+ if (-not $excelFiles -or $excelFiles.Count -eq 0 ) {
9+ Write-Error " No .xlsx file found in: $scriptDir "
10+ exit 1
11+ }
12+
13+ if ($excelFiles.Count -eq 1 ) {
14+ $ExcelFile = $excelFiles [0 ]
15+ Write-Host " Excel file selected: $ ( $ExcelFile.Name ) "
16+ } else {
17+ Write-Host " Multiple .xlsx files found in the folder:"
18+ for ($i = 0 ; $i -lt $excelFiles.Count ; $i ++ ) {
19+ Write-Host " [$i ] $ ( $excelFiles [$i ].Name) "
20+ }
21+ $fileIndex = Read-Host " Enter the number of the Excel file to use"
22+ if ($fileIndex -notmatch ' ^\d+$' -or [int ]$fileIndex -lt 0 -or [int ]$fileIndex -ge $excelFiles.Count ) {
23+ Write-Error " Invalid selection. Exiting."
24+ exit 1
25+ }
26+ $ExcelFile = $excelFiles [$fileIndex ]
27+ Write-Host " Excel file selected: $ ( $ExcelFile.Name ) "
28+ }
29+
30+ # --- Sheet Name ---
31+ $SheetName = Read-Host " Enter the Excel sheet name (SheetName)"
32+ if ([string ]::IsNullOrWhiteSpace($SheetName )) {
33+ Write-Error " SheetName not provided. Exiting script."
34+ exit 1
35+ }
36+
37+ # --- SQL Table Name ---
38+ $SqlTableName = Read-Host " Enter the SQL table name (SqlTableName)"
39+ if ([string ]::IsNullOrWhiteSpace($SqlTableName )) {
40+ Write-Error " SqlTableName not provided. Exiting script."
41+ exit 1
42+ }
43+
44+ # --- Output File Name ---
45+ $defaultOutput = " create_table.txt"
46+ $outputInput = Read-Host " Enter the output file name (press Enter for default: $defaultOutput )"
47+ if ([string ]::IsNullOrWhiteSpace($outputInput )) {
48+ $OutputFile = Join-Path $PSScriptRoot $defaultOutput
49+ } else {
50+ $OutputFile = Join-Path $PSScriptRoot $outputInput
51+ }
52+
53+ # --- Type Detection Threshold ---
54+ $defaultThreshold = 500
55+ $thresholdInput = Read-Host " Enter threshold for type detection (press Enter for default: $defaultThreshold )"
56+ if ([string ]::IsNullOrWhiteSpace($thresholdInput )) {
57+ $TypeThreshold = $defaultThreshold
58+ } else {
59+ if ($thresholdInput -as [int ]) {
60+ $TypeThreshold = [int ]$thresholdInput
61+ } else {
62+ Write-Error " Invalid threshold. Using default value: $defaultThreshold "
63+ $TypeThreshold = $defaultThreshold
64+ }
65+ }
66+
67+ Write-Host " Excel file: $ ( $ExcelFile.FullName ) "
68+ Write-Host " Sheet: $SheetName "
69+ Write-Host " SQL table: $SqlTableName "
70+ Write-Host " Output: $OutputFile "
71+
72+ # --- ImportExcel Module ---
73+ if (-not (Get-Module - ListAvailable - Name ImportExcel)) {
74+ Install-Module - Name ImportExcel - Scope CurrentUser - Force
75+ }
76+ Import-Module ImportExcel
77+
78+ # --- Read Data from Sheet ---
79+ try {
80+ $data = Import-Excel - Path $ExcelFile.FullName - WorksheetName $SheetName
81+ } catch {
82+ Write-Error " Error importing XLSX file: $ ( $_.Exception.Message ) "
83+ exit 1
84+ }
85+ if (-not $data -or $data.Count -eq 0 ) {
86+ Write-Error " Sheet is empty or unreadable."
87+ exit 1
88+ }
89+
90+ # --- Get Actual Column Names ---
91+ $columnNames = $data | Get-Member - MemberType NoteProperty | Select-Object - ExpandProperty Name
92+
93+ # --- Handle Duplicate Headers ---
94+ $finalHeaders = @ ()
95+ $uniqueHeaders = @ {}
96+ $duplicates = @ ()
97+ foreach ($c in $columnNames ) {
98+ $colName = if ($null -eq $c -or " $c " .Trim() -eq " " ) { " UnnamedColumn" } else { " $c " .Trim() }
99+ $baseName = $colName
100+ $i = 2
101+ while ($finalHeaders -contains $colName ) {
102+ if (-not ($duplicates -contains $baseName )) { $duplicates += $baseName }
103+ $colName = " ${baseName} _$i " ; $i ++
104+ }
105+ $finalHeaders += $colName
106+ $uniqueHeaders [$finalHeaders.Count - 1 ] = $colName
107+ }
108+ if ($duplicates.Count -gt 0 ) {
109+ Write-Host " WARNING: Duplicate columns found and renamed: $ ( $duplicates -join ' , ' ) "
110+ } else {
111+ Write-Host " No duplicate columns detected."
112+ }
113+
114+ function Get-SqlTypeAndLength ($colName , $values ) {
115+ # Clean: convert all to string, remove nulls and empty/whitespace strings
116+ $cleanValues = $values | Where-Object { $_ -ne $null } | ForEach-Object { " $_ " .Trim() }
117+ $nonNullValues = $cleanValues | Where-Object { $_ -match ' \S' }
118+
119+ if ($nonNullValues.Count -eq 0 ) {
120+ if ($colName -match ' (?i)data|date' ) { return @ {Type = " DATETIME" ; Length = $null } }
121+ else { return @ {Type = " NVARCHAR" ; Length = 100 } }
122+ }
123+
124+ $intCount = ($nonNullValues | Where-Object { $_ -match ' ^-?\d+$' } | Measure-Object ).Count
125+ $floatCount = ($nonNullValues | Where-Object { $_ -match ' ^-?\d+\.\d+$' } | Measure-Object ).Count
126+ $dateCount = ($nonNullValues | Where-Object {
127+ try { [datetime ]::Parse($_ ) | Out-Null ; $true } catch { $false }
128+ } | Measure-Object ).Count
129+ $boolCount = ($nonNullValues | Where-Object {
130+ $t = $_.ToLower ()
131+ $t -eq " true" -or $t -eq " false" -or $t -eq " 0" -or $t -eq " 1"
132+ } | Measure-Object ).Count
133+
134+ if ($intCount -ge $TypeThreshold -and $intCount -eq $nonNullValues.Count ) {
135+ return @ {Type = " INT" ; Length = $null }
136+ } elseif ($boolCount -ge $TypeThreshold -and $boolCount -eq $nonNullValues.Count ) {
137+ return @ {Type = " BIT" ; Length = $null }
138+ } elseif ($floatCount -ge $TypeThreshold -and $floatCount -eq $nonNullValues.Count ) {
139+ return @ {Type = " FLOAT" ; Length = $null }
140+ } elseif ($dateCount -ge $TypeThreshold -and $dateCount -eq $nonNullValues.Count ) {
141+ return @ {Type = " DATETIME" ; Length = $null }
142+ } else {
143+ # NVARCHAR: calculate max length
144+ $maxLen = ($nonNullValues | ForEach-Object { $_.Length } | Measure-Object - Maximum).Maximum
145+ $maxAllowed = 255
146+ $colLength = [Math ]::Min($maxLen , $maxAllowed )
147+ return @ {Type = " NVARCHAR" ; Length = $colLength }
148+ }
149+ }
150+
151+ # --- Analyze Columns and Detect SQL Types ---
152+ $Columns = @ ()
153+ for ($i = 0 ; $i -lt $finalHeaders.Count ; $i ++ ) {
154+ $colName = $finalHeaders [$i ]
155+ $propName = $columnNames [$i ]
156+ $values = @ ()
157+ foreach ($row in $data ) {
158+ $cellValue = $row .$propName
159+ $values += $cellValue
160+ }
161+ $typeInfo = Get-SqlTypeAndLength $colName $values
162+ $CleanCol = $colName -replace ' [^a-zA-Z0-9_]' , ' _'
163+ $sqlType = if ($typeInfo.Type -eq " NVARCHAR" ) { " NVARCHAR($ ( $typeInfo.Length ) )" } else { $typeInfo.Type }
164+ Write-Host " $colName -> $sqlType "
165+ $Columns += " [$CleanCol ] $sqlType "
166+ }
167+
168+ $ColumnsSql = $Columns -join " ,`n "
169+ $CreateTable = " CREATE TABLE [$SqlTableName ] (`n $ColumnsSql `n );"
170+
171+ Set-Content - Path $OutputFile - Value $CreateTable - Encoding UTF8
172+ Write-Host " SQL command generated and saved to: $OutputFile "
173+
174+ # --- Output Preview ---
175+ Write-Host " === OUTPUT FILE CONTENT: $OutputFile ==="
176+ Get-Content - Path $OutputFile | Write-Host
177+
178+ Write-Host " === END OF SCRIPT ==="
0 commit comments