sql >> Databasteknik >  >> RDS >> Database

Python-databasprogrammering med SQL Express för nybörjare

Python har vuxit explosivt i popularitet under de senaste 5 åren. Många nya programmerare dras till det på grund av dess milda inlärningskurva i förhållande till andra programmeringsspråk. Erfarna programmerare dras till det på grund av dess töjbarhet och kraft. Men en av de viktigaste drivkrafterna för denna massintroduktion är hur lätt Python kan arbeta med databaser. Den här Python-programmeringshandledningen kommer att utforska hur du kommer igång med att använda Python för att kommunicera med SQL Express med Python 3.

Python- och databasprogrammering

En Python-nybörjare som vill integrera databasfunktioner i alla mjukvaruprojekt skrivet i alla språk måste ha en grundläggande förståelse för minst två språk. Det första är naturligtvis Python och det andra är det specifika strukturerade frågespråket (SQL) som används av databasen. Även om SQL är standardiserat är det i praktiken inte ett universellt språk, men implementeringarna mellan olika databaser är tillräckligt nära för att flytta från en databas till en annan inte är så stor utmaning när man väl har en bekväm nivå av erfarenhet av databasapplikationsutveckling.

En annan viktig faktor för databaser är att de alla kräver hanteringsprogramvara. Dessa hanteringsverktyg kan hjälpa till med att ställa in åtkomst till och säkerhetsprivilegier inom en databas. De kan också användas för att felsöka databasapplikationer eftersom de kan göra det möjligt för en utvecklare att göra saker som:

  • Skapa och hantera innehållet i tabeller, vyer och andra databasobjekt. Detta inkluderar relationerna mellan tabeller, såväl som konfigurationen av integritetsregler.
  • Interaktion med databasen direkt via SQL-kodinmatning.
  • Felsökning av SQL-syntax.
  • Ångra (i viss utsträckning) av skada som orsakats av felaktigt kodade SQL-satser i programmet.

Även om en utvecklare väljer att använda en noSQL-baserad databas som MongoDB, kommer det fortfarande att finnas utmaningar med att lära sig den databasspecifika kodningssyntax som behövs för att få en sådan lösning att fungera. Naturligtvis är dessa inte avskräckande, de är bara tekniska faktorer som måste beaktas med alla programvaruutvecklingsprojekt.

Python- och databasdrivrutiner

Python, som alla andra programmeringsspråk, kan inte kommunicera med en given databas. Det kräver att extra moduler läggs till för en specifik databasserver. Ur bästa praxissynpunkt är det bäst att använda en databasdrivrutinsmodul som är specifik för den databasserver som valts för programvaruprojektet. Genom att göra det säkerställer du att Python kan komma åt alla funktioner i databasservern, även om det kostar extra att använda en specifik programmeringssyntax för modulen. Även om vissa försök har gjorts för att skapa "universella" databasdrivrutinsmoduler som kan ansluta till flera databasservrar, kommer dessa ofta på bekostnad av att förlora åtkomst till vissa funktioner hos en viss databasserver.

Vad är SQL Express?

SQL Server har varit den bästa databasserverlösningen för Windows i decennier. Även om det är ungefär så långt ifrån en gratis databasserverlösning som man kan komma, tillhandahåller Microsoft en avskalad variant av SQL Server som heter SQL Express utan kostnad. SQL Express är ett idealiskt inlärningsverktyg för nybörjare eftersom det stöder samma SQL-syntax som SQL Server använder. Både SQL Express och SQL Server använder en anpassad tillägg av SQL som kallas "Transact-SQL", även känd som "T-SQL." Både SQL Express och SQL Server stöder användningen av Windows-användarkonton och traditionella användarnamn och lösenordssystem för åtkomsthantering.

Python kommunicerar med SQL Express eller SQL Server med en modul som heter PyODBC . Både SQL Server och SQL Express hanteras av en separat, gratis Windows-applikation som kallas "SQL Server Management System", populärt känt som "SSMS". När detta skrivs är både SQL Express och SSMS separata nedladdningar från Microsoft:

  • SSMS-nedladdning
  • SQL Express-nedladdning

Hur man konfigurerar SQL Express för Python-utveckling

SQL Express, liksom SQL Server, stöder två typer av autentisering. Den första är autentisering baserad på en användares Windows-användarkonto, även känd som en "Trusted Connection". Den andra är traditionellt användarnamn och lösenordsbaserad autentisering implementeras i vad som kallas "Mixed Mode Authentication." Mixed Mode-autentisering stöder både Windows-användarkontobaserad autentisering och användarnamn- och lösenordsbaserad autentisering. Det finns inget sätt att stödja användarnamn och lösenordsbaserad autentisering i sig själv i SQL Server eller SQL Express.

Microsoft har gått bort från Mixed Mode Authentication, eftersom en av de stora fördelarna med att använda Trusted Connections är att databasuppgifterna inte behöver lagras i applikationskoden. Demonstrationen i den här artikeln kommer inte heller att använda den.

Kopierar INTE anslutningssträngen efter installation

En stridspunkt för applikationsutvecklare på nybörjarnivå är den initiala förvirringen kring SQL Server-anslutningssträngar. Om man installerar SQL Express tillhandahåller installationsprogrammet anslutningssträngen för den skapade SQL Express-instansen efter installationen. Tyvärr kommer anslutningssträngen troligen inte att fungera med PyODBC . Även om det är frestande att "invaggas" till en känsla av säkerhet med denna "gratis" kommer det att orsaka mer problem än det är värt.

Figur 1 – Hämta anslutningssträngen från SQL Express Installer

Observera att när detta skrivs innehåller installationsprogrammet för SQL Express även en länk för att ladda ner SSMS-installationsprogrammet.

Hur man skapar en databas i SQL Express

När både SQL Express och SSMS är installerade är det dags att skapa en grundläggande databas med lämpliga åtkomstbegränsningar. Det enklaste sättet att starta SSMS är att klicka på Start knappen i Windows, skriv in "ssms" i sökfältet, vänta tills "Microsoft SQL Server Management Studio 18" visas i det övre högra hörnet och klicka sedan på Öppna länk till höger på startmenypanelen:

Figur 2 – Starta SSMS

När man startar SSMS möts man av följande dialogruta:

Figur 3 – SSMS-öppningsdialog

Med Windows-autentisering behöver du inte ange några inloggningsuppgifter. Windows-användarkontot under vilken SQL Express installerades har administratörsbehörighet för SQL Express-instansen. Klicka bara på Anslut för att fortsätta.

Längst till vänster i SSMS Application Window , kommer det att finnas Objektutforskaren . För att skapa en ny databas, högerklicka på Databaser och välj Skapa databas från Kontext meny:

Figur 4 – Skapa en ny databas – Del 1 av 2

Klicka på Ny databas... kommer att öppna ett nytt dialogfönster som gör det möjligt att mata in uppgifterna om den nya databasen. För denna demonstration kommer databasen att kallas RazorDemo , som lite av en återgång till en tidigare artikel om att utveckla Razor-baserade applikationer i C#. Ange namnet på databasen i textrutan bredvid Databasnamn och klicka sedan på OK knappen längst ned i dialogfönstret. Observera att kolumnerna för det Logiska namnet i illustrationen nedan av filerna breddades något så att de fullständiga Logiska namnen av databasfilerna som skapas exponerades:

Figur 5 – Skapa en ny databas – Del 2 av 2

Den nya databasen visas sedan i Objektutforskaren under Databaser mapp:

Figur 6 – Den nyskapade "RazorDemo"-databasen

Hur man skapar tabeller i SQL Express

En relationsdatabas är inte riktigt användbar utan tabeller för att lagra data, och det enklaste sättet att skapa dessa tabeller är att använda SQL-kod. Observera att man kan använda Table Creation Wizard att skapa en tabell är det snabbare, enklare och mycket enklare att använda SQL-kod. Börja med att högerklicka på RazorDemo databaspost, vänsterklicka sedan på Ny fråga alternativ i sammanhangsfönstret:

Figur 7 – Öppna ett nytt frågefönster

Ett frågeredigeringsfönster som liknar det nedan visas till höger om Objektutforskaren :

Figur 8 – Frågeredigeringsfönstret

Koden för att skapa tabeller visas i listan nedan:

use RazorDemo;  # See the Important Note below

create table artists
(rcdid int not null identity primary key,
artist_name varchar(max));

create table albums
(rcdid int not null identity primary key,
artist_id int not null references artists(rcdid) on delete cascade,
album_name varchar(max));
         

Listing 1 - Table Creation SQL Code

Observera när du skapar ett Frågeredigeringsfönster från databasen garanterar vanligtvis att den valda databasen kommer att vara den mot vilken koden exekveras, är det en bra idé att alltid uttryckligen använda den avsedda databasen i början av koden. användningen kommandot väljer uttryckligen namnet på databasen som följer det.

Tryck på F5 eller klicka på Kör knappen kommer att köra satserna mot RazorDemo databas. Om exekveringen lyckas visas ett meddelande som anger det i "Meddelanden ruta nedan:

Figur 9 – Framgångsrik tabellskapande

De nyskapade tabellerna och deras kolumner kan ses i Objektutforskaren också. Observera att ibland Uppdatera alternativ från snabbmenyn som visas när du högerklickar på databasen kan behöva väljas för att visa nya objekt i en databas:

Figur 10 – Uppdatera objektutforskaren


Figur 11 – De nya tabellerna och deras kolumner

Vid denna tidpunkt kan SSMS stängas säkert.

Observera att SSMS fungerar på samma sätt med vilken SQL Server-databas som helst. Det är alltid en bästa praxis att spara all kod för att skapa tabeller oavsett vilken databasserver som används. Även om SQL Server och SQL tillåter återställning av sådana skript, tillåter de båda användningen av kryptering på sådana satser också, och i dessa fall kan koden inte återställas.

Python och SQL Express

Normalt skulle en diskussion om SQL Server-säkerhet behövas här, men eftersom Trusted Connections kommer att användas så länge som den pågående processen som kör Python-koden ägs av en Windows-användare som redan har tillgång till en databas som nås, kommer den diskussionen inte att behövas. Tänk på att både SQL Server och SQL Express erbjuder mycket robusta säkerhetsrelaterade anpassningar, men de ligger utanför ramen för en artikel avsedd för nybörjare.

Notera, skölj inte över korrekt databassäkerhet för någon applikation som körs i en produktionsmiljö! Se till att endast minsta möjliga behörighet ges till användarkontot som skulle komma åt en databas i en projektionsmiljö.

Den version av Python som används för dessa kodexempel är 3.10, och den installerades via Microsoft Store i Windows. Om du installerar Python med den här metoden kommer Python och PIP3 körbara filer att läggas till i systemsökvägen, så att de fullständiga sökvägarna till dessa kommandon inte behöver skrivas i Kommandotolken fönster. För kodinmatning är en bra textredigerare utan kostnad Notepad++.

Öppna kommandotolken Windows

Att köra Python-kod görs bäst via Kommandotolken . För att komma åt Kommandotolken klickar du på Start i Windows och ange cmd i sökfältet. Vänta på Kommandotolken visas och klicka sedan på Öppna länken till höger på Startmenyn :

Figur 12 – Öppna en kommandotolk

En typisk Kommandotolk fönstret ser ut så här:

Figur 13 – En typisk kommandotolk

Hur man installerar PyODBC

PyODBC är Python-modulen som gör det möjligt för Python att komma åt både SQL Server och SQL Express. Vid installation av Python via Microsoft Store, PyODBC kan läggas till i Python via kommandot:

pip3 install pyodbc

Figur 14 – Lyckad installation av PyODBC

Observera att om det finns flera versioner av Python installerade, till exempel både Python 2 och Python 3, kan det vara nödvändigt att prefixet pip3 kommandot med den fullständiga Windows-sökvägen till kommandot för lämplig version av Python.

Observera också att om bara Python 3 är installerat, är pip3 kommandot ska fortfarande användas över det mer generiska pip kommandot, eftersom detta är rätt konvention.

Skriva Python-kod

Nu när databasen är konfigurerad och PyODBC är installerade, kan databasen fyllas i. I fallet med en databas som katalogiserar artister och album räcker det med några slumpmässigt genererade bandnamn och album. Python-koden för att ansluta till databasen ingår också, men inläggen är inte (ännu):

# bad-band-name-maker.py
import sys
import random
import pyodbc

part1 = ["The", "Uncooked", "Appealing", "Larger than Life", "Drooping", "Unwell", "Atrocious", "Glossy", "Barrage", "Unlawful"]
part2 = ["Defeated", "Hi-Fi", "Extraterrestrial", "Adumbration", "Limpid", "Looptid", "Cromulent", "Unsettled", "Soot", "Twinkle"]
part3 = ["Brain", "Segment", "Audio", "Legitimate Business", "Mentality", "Sound", "Canticle", "Monsoon", "Preserves", "Hangout"]

part4 = ["Cougar", "Lion", "Lynx", "Ocelot", "Puma", "Jaguar", "Panther"]
part5 = ["Fodder", "Ersatz Goods", "Leftovers", "Infant Formula", "Mush", "Smoothie", "Milkshakes"]


def main(argv):
  # Connect to the RazorDemo database.
  conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;")

  # Generate 15 bad band names:
  for x in range(1, 16):
    rand1 = random.randrange(0, 9)
    rand2 = random.randrange(0, 9)
    rand3 = random.randrange(0, 9)
    badName = part1[rand1] + ' ' + part2[rand2] + ' ' + part3[rand3]
    print ("Band name [" + str(x) + "] is [" + badName + "]")
  
    for y in range(1, 3):
      rand4 = random.randrange(0, len(part4))
      rand5 = random.randrange(0, len(part5))
      albumName = part4[rand4] + " " + part5[rand5]
      print ("\tAlbum [" + albumName + "]")
      
  # Close the Connection
  conn.close()
  return 0

if __name__ == "__main__":
	main(sys.argv[1:])



Listing 2 - Making up some data

Detta ger följande utdata:

Figur 15 – Slumpmässigt genererade bandnamn

Notera användningen av cd kommandot för att byta till katalogen där Python-koden sparas. PyODBC connect() funktionen misslyckas om det för närvarande inloggade Windows-användarkontot är inte listad med åtkomst i SQL Express. Detta är bara ett problem om databasen skapas med ett Windows-användarkonto men koden körs under ett annat Windows-användarkonto .

Det minst sämsta sättet att INFOGA data i SQL och PyODBC

Många nybörjare Python-utvecklare frestas att ringa till PyODBC anrop till INSERT uttalanden i följande avsnitt av koden, och i samband med vad som kommer att anges härnäst, är detta ingen dålig idé:

Figur 16 – Det "nästan" fel sättet att arbeta med en databas

Anledningen till att man använder anrop till PyODBC för att utföra INSERT , VAL , och andra databasrelaterade funktioner, såsom UPPDATERA eller RADERA , inom loopar kan vara dåligt eftersom det finns overhead som kommer med vart och ett av dessa samtal. Inom en loop som potentiellt skulle kunna iterera hundratals gånger, tusentals gånger eller till och med mer, kan detta resultera i en betydande tid (minuter eller mer) att köra igenom ett skript. För webbapplikationer som använder ett sådant tillvägagångssätt förvärras prestandaproblemen ytterligare, eftersom många webbservrar sätter hårda tak för hur lång tid ett skript kan köras. Skicka aldrig under några omständigheter användarskapade indata direkt till en databas. Kontrollera alltid inmatningen för att säkerställa att den inte kommer att bryta databasfunktionalitet eller orsaka ett säkerhetsproblem i form av en SQL Injection-attack.

Helst skulle man vilja använda slingorna ovan för att skapa en SQL-batch (en lista med satser) och sedan ha PyODBC kör på den enda batchen, men det skulle vara en mycket dålig idé om data inte saneras.

Varför skulle uppgifterna behöva saneras? Anledningen handlar om säkerhet, eftersom användarinput aldrig kan lita på. Att sanera data innebär att representera den på ett sätt som förhindrar att något annat än SQL-satsen som skapats av utvecklaren av programmet exekveras. En användare kan skicka en uppsåtligt konstruerad sträng som skulle möjliggöra exekvering av godtyckligt skapad SQL-kod. Detta är känt som en SQL Injection attack. Även om datavärden som ingår i en batch kan saneras, ligger processen för att göra det utanför ramen för en inledande självstudie.

PyODBC tillhandahåller en mekanism för att skydda databasen från SQL Injection-attacker genom att sanera användarinmatningar. Dessa involverar användning av parameteriserade uttalanden , även kallad förberedda uttalanden . Säkerhet måste alltid vara en prioritet, även om det sker på bekostnad av hastighet eller andra prestandamått.

Windows-användarkontot som har åtkomst till denna databas har som standard systemadministratörsbehörigheter. Detta innebär att om en SQL Injection-attack skulle inträffa kan en illvillig användare få tillgång till all data i varje databas på servern. I praktiken bör inget konto med sysadmin-behörighet ha åtkomst till någon databas från Python-kod.

Listan nedan förstärker det första Python-kodexemplet genom att använda PyODBC markörer för att infoga data:

# bad-band-name-maker2.py
import sys
import random
import pyodbc

part1 = ["The", "Uncooked", "Appealing", "Larger than Life", "Drooping", "Unwell", "Atrocious", "Glossy", "Barrage", "Unlawful"]
part2 = ["Defeated", "Hi-Fi", "Extraterrestrial", "Adumbration", "Limpid", "Looptid", "Cromulent", "Unsettled", "Soot", "Twinkle"]
part3 = ["Brain", "Segment", "Audio", "Legitimate Business", "Mentality", "Sound", "Canticle", "Monsoon", "Preserves", "Hangout"]

part4 = ["Cougar", "Lion", "Lynx", "Ocelot", "Puma", "Jaguar", "Panther"]
part5 = ["Fodder", "Ersatz Goods", "Leftovers", "Infant Formula", "Mush", "Smoothie", "Milkshakes"]


def main(argv):
  # Connect to the RazorDemo database.
  conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;")

  # Generate 15 bad band names, and try to keep them unique.
  previousNames = ""
  nameCount = 0
  while (nameCount < 16):
    rand1 = random.randrange(0, 9)
    rand2 = random.randrange(0, 9)
    rand3 = random.randrange(0, 9)
    badName = part1[rand1] + ' ' + part2[rand2] + ' ' + part3[rand3]
    # A crude but effective way of ensuring uniqueness, although there is no unique constraint on the artist name in the database.
    # This prepends and appends bars to both the list of previously used names and the current name. If the current name is
    # new, it will not be in that string.
    if ("|" + previousNames + "|").find("|" + badName + "|") == -1: 
      print ("Band name [" + str(nameCount) + "] is [" + badName + "]")
      sql1 = "insert into artists (artist_name) values (?)"
      values1 = [badName]
      rs1 = conn.cursor()
      rs1.execute(sql1, values1)
      rs1.commit()
      # If the cursor is not closed, then other cursors cannot be executed.
      rs1.close()
      for y in range(1, 3):
        rand4 = random.randrange(0, len(part4))
        rand5 = random.randrange(0, len(part5))
        albumName = part4[rand4] + " " + part5[rand5]
        print ("\tAlbum [" + albumName + "]")
        sql2 = "insert into albums (artist_id, album_name) values ((select top 1 rcdid from artists where artist_name=?), ?)"
        # Each array item here corresponds to the position of the ? in the SQL statement above.
        values2 = [badName, albumName]
        rs2 = conn.cursor ()
        rs2.execute(sql2, values2)
        rs2.commit()
        rs2.close()
      # Creates a bar-delimited list of previously used names.
      if previousNames == "":
        previousNames = badName
      else:
        previousNames = previousNames + "|" + badName
      nameCount = 1 + nameCount
    else:
      print ("Found a duplicate of [" + badName + "]")
  #print (previousNames)
  # Close the Connection
  conn.close()
  return 0

if __name__ == "__main__":
	main(sys.argv[1:])





Listing 3 - Inserting the data

Följande fråga kan köras i SSMS för att verifiera utmatningen av koden:

Figur 17 – Den framgångsrika infogningen av data

Välja data i SQL Express och Python

Nu när det finns data i databasen skulle det vara trevligt att fråga efter det. Nedan finns ett enkelt skript som accepterar användardata från tangentbordet och skickar det till databasen via en parametrerad fråga:

# bad-band-name-maker3.py
import sys

import pyodbc

def main(argv):
  searchValue = input("Enter something: ")
  # Cap the length at something reasonable. The first 20 characters.
  searchValue = searchValue[0:20]
  # Set the search value to lower case so we can perform case-insensitive matching:
  searchValue = searchValue.lower()
  
  # Connect to the RazorDemo database.
  conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};Server=localhost\SQLEXPRESS;Database=RazorDemo;Trusted_Connection=yes;")

  # You must use a parameterized query here in order to protect from SQL Injection Attacks!
  
  # For the like operator, the percent signs must be separated from the term or else the parameterization will fail.
  
  sql1 = ("select a.artist_name, b.album_name from artists a, albums b where b.artist_id = a.rcdid and " +
    "lower(album_name) like ('%' + ? + '%') order by a.artist_name, b.album_name")
  # Below is an array with one element:
  values1 = [searchValue]
  rs1 = conn.cursor()
  rs1.execute(sql1, values1)
  rows1 = rs1.fetchone()
  #print ("Type is [" + str(type(rows1)) + "]")
  if str(type(rows1)).find("NoneType") == -1:
    while rows1:
      # Columns are indexed by number only. 0 is the a.artist_name column and 1 is the b.album_name columns
      print(rows1[0] + " - " + rows1[1])
      rows1 = rs1.fetchone()
  else:
    print ("No album name matched [" + searchValue + "]")
  # Close the Connection
  conn.close()

  return 0

if __name__ == "__main__":
	main(sys.argv[1:])



Listing 4 - Querying the Data

Samma resultat. En inkluderar till och med ett exempel på en grov SQL Injection-attack:

Figur 18 – Frågeresultat. Notera det senaste sökvärdet.

Sluta tankar om Python-databasutveckling

Det finns verkligen ingen gräns för vilka SQL Server-drivna applikationer som kan utvecklas med Python. En utvecklare är bara begränsad av kunskap om SQL, och förhoppningsvis kan de grundläggande koncepten som presenteras i den här artikeln peka en utvecklare på nybörjarnivå i rätt riktning när det gäller att bredda sin förståelse av SQL och bygga mer komplexa applikationer.

Denna handledning för programmering av Python-databas presenterade sätt med vilka SQL Express kunde installeras som ett utvecklingsstöd för SQL Server, och visade hur Python 3 kan utökas för att korrekt kommunicera med en SQL Express-databasinstans på den servern. Den här artikeln visade också hur SQL Server Management Studio ska användas för att hantera alla SQL Express- eller SQL Server-databaser. För att gå längre, berörde den här artikeln också grundläggande säkerhetsåtgärder och användningen av effektiv kodning i syfte att säkerställa rimliga körtider för SQL Server-drivna applikationer.


  1. Hur man hämtar ett OBJECT_NAME() från en annan databas i SQL Server

  2. Varför ger mysqli ett kommandon osynkroniserat fel?

  3. Utvecklarverktyg för direkt åtkomst till databaser

  4. Allt du behöver veta om databasnormalisering