Pandas & NumPy Academy · บทเรียน

การเรียกใช้คำสั่ง SQL จาก Pandas

ดำเนินการคำสั่ง SELECT ใด ๆ ด้วย pd.read_sql_query และกำหนดพารามิเตอร์ให้คำสั่งอย่างปลอดภัยเพื่อป้องกัน SQL injection

บทเรียน 2 จาก 413 ขั้นตอน

การเรียกใช้คำสั่ง SQL จาก Pandas เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

pd.read_sql: อินเทอร์เฟซแบบรวม

Pandas มี ฟังก์ชันสำหรับอ่านข้อมูล SQL สามฟังก์ชัน ได้แก่ pd.read_sql() (ตัวห่อหุ้มทั่วไป), pd.read_sql_table() (อ่านตารางทั้งหมดตามชื่อ) และ pd.read_sql_query() (เรียกใช้ SQL ใด ๆ) สำหรับกระบวนการวิเคราะห์ส่วนใหญ่ pd.read_sql_query() มีความสามารถมากที่สุด เพราะช่วยให้คุณเขียนคำสั่ง SELECT ใด ๆ พร้อมการกรอง การเชื่อมตาราง และการรวมข้อมูลก่อนที่ข้อมูลจะเข้าสู่ Pandas การใช้ SQL จัดการงานหนัก แล้วใช้ Pandas สำหรับการวิเคราะห์ขั้นสุดท้าย มักมีประสิทธิภาพกว่าการโหลดทุกอย่างแล้วกรองด้วย Python

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///ecommerce.db')

# Three equivalent patterns
df1 = pd.read_sql('SELECT * FROM orders LIMIT 100', con=engine)
df2 = pd.read_sql_table('orders', con=engine)  # full table
df3 = pd.read_sql_query('SELECT * FROM orders LIMIT 100', con=engine)

print(df3.head())
print(df3.columns.tolist())

การกรองข้อมูลในระดับฐานข้อมูล

กรองข้อมูลใน SQL เสมอ แทนที่จะโหลดทุกอย่างแล้วกรองใน Pandas ฐานข้อมูลที่มีดัชนีเหมาะสมสามารถดำเนินการกับเงื่อนไข WHERE บนแถวหลายล้านแถวและส่งกลับมาเพียงหลักพันแถวภายในเวลาไม่กี่มิลลิวินาที ขณะที่ Pandas ต้องโหลดข้อมูลระดับกิกะไบต์เสียก่อน กฎสำคัญคือ ส่งเงื่อนไขไปให้ฐานข้อมูลประมวลผล ใช้ WHERE สำหรับกรองแถว ใช้ SELECT col1, col2 สำหรับเลือกคอลัมน์ และใช้ LIMIT ระหว่างการพัฒนาเพื่อดูตัวอย่างผลลัพธ์อย่างรวดเร็ว

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

# Filter and project at SQL level — only fetch what you need
query = '''
    SELECT order_id, customer_id, amount, status
    FROM orders
    WHERE status = 'completed'
      AND order_date >= '2024-01-01'
      AND amount > 50
    LIMIT 1000
'''

df = pd.read_sql_query(query, con=engine)
print(f'Rows: {len(df)}, Columns: {list(df.columns)}')

การรวมข้อมูลใน SQL เทียบกับ Pandas

สำหรับสรุปข้อมูลระดับกลุ่มแบบง่ายจากตารางขนาดใหญ่ การรวมข้อมูลด้วย SQL มีประสิทธิภาพเหนือกว่า Pandas เพราะเครื่องมือฐานข้อมูลสามารถใช้ดัชนี การประมวลผลแบบขนาน และการรวมข้อมูลด้วยแฮชบนดิสก์ได้ ใช้ SQL กับ GROUP BY และ SUM/COUNT/AVG เมื่อตารางมีขนาดใหญ่ จากนั้นโหลดผลลัพธ์ที่รวมแล้ว (DataFrame ขนาดเล็ก) เข้าสู่ Pandas เพื่อวิเคราะห์ แสดงภาพ หรือรวมกับข้อมูลอื่นต่อไป สำหรับการรวมข้อมูลแบบกำหนดเองที่ซับซ้อนและ SQL ไม่สามารถแสดงได้ ให้โหลดข้อมูลบางส่วนที่กรองแล้วเข้าสู่ Pandas และใช้ groupby ที่นั่น

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

# Aggregate in SQL — returns a small result set
query = '''
    SELECT region,
           COUNT(*) AS order_count,
           ROUND(SUM(amount), 2) AS total_revenue,
           ROUND(AVG(amount), 2) AS avg_order_value
    FROM orders
    WHERE status = 'completed'
    GROUP BY region
    ORDER BY total_revenue DESC
'''

df = pd.read_sql_query(query, con=engine)
print(df)

JOIN ในคำค้น SQL

การดำเนินการ JOIN ของ SQL มีประสิทธิภาพมากกว่า merge() ของ Pandas เมื่อเชื่อมตารางขนาดใหญ่ เพราะฐานข้อมูลสามารถใช้การค้นหาผ่านดัชนีได้ เขียนการเชื่อมตารางใน SQL แล้วรับผลลัพธ์ที่เชื่อมตารางและอาจกรองแล้วมาไว้ใน Pandas สำหรับการวิเคราะห์หลายตาราง คำค้น SQL เดียวที่มี JOIN หลายรายการมักเร็วกว่าการอ่านแต่ละตารางแยกกันแล้วรวมด้วย Pandas โดยเฉพาะเมื่อหนึ่งในตารางมีหลายล้านแถวและการเชื่อมตารางช่วยลดขนาดผลลัพธ์ลงอย่างมาก

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///ecommerce.db')

query = '''
    SELECT o.order_id,
           c.customer_name,
           c.country,
           p.product_name,
           o.amount
    FROM orders o
    JOIN customers c ON o.customer_id = c.id
    JOIN products p ON o.product_id = p.id
    WHERE o.status = 'completed'
    LIMIT 500
'''

df = pd.read_sql_query(query, con=engine)
print(df.head())

การใช้ตัวแปร Python ในคำค้น

หากต้องการแทรกตัวแปร Python ลงในคำค้น SQL อย่างปลอดภัย ให้ใช้ text() ของ SQLAlchemy พร้อมพารามิเตอร์ที่ตั้งชื่อ กำหนดตัวแทนค่าด้วย :param_name ในสตริงคำค้น แล้วส่งพจนานุกรมให้กับอาร์กิวเมนต์ params ของ read_sql_query วิธีนี้ใช้ได้ทั้งกับค่าเดียวและกับรายการค่าในฐานข้อมูลบางชนิด หลีกเลี่ยง f-string หรือการจัดรูปแบบด้วย % เพื่อสร้างสตริงคำค้นจากตัวแปร เพราะไม่ปลอดภัยแม้จะใช้ภายในก็ตาม

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

# Python variables to inject
min_amount = 200.0
start_date = '2024-01-01'
end_date = '2024-12-31'

query = sa.text('''
    SELECT * FROM orders
    WHERE amount > :min_amount
      AND order_date BETWEEN :start_date AND :end_date
''')

with engine.connect() as conn:
    df = pd.read_sql_query(query, con=conn,
                           params={'min_amount': min_amount,
                                   'start_date': start_date,
                                   'end_date': end_date})
print(f'{len(df)} orders found')

การใช้ CTE และคำค้นย่อย

การวิเคราะห์ที่ซับซ้อนมักต้องใช้ นิพจน์ตารางทั่วไป (CTE) หรือคำค้นย่อย ทั้งสองแบบรองรับโดย pd.read_sql_query อย่างสมบูรณ์ เพียงส่ง SQL หลายส่วนทั้งหมดเป็นสตริงคำค้น CTE (เริ่มต้นด้วยคีย์เวิร์ด WITH) ทำให้คำค้นที่ซับซ้อนอ่านง่ายขึ้นด้วยการตั้งชื่อให้ผลลัพธ์ระหว่างทาง วิธีนี้มีประโยชน์สำหรับการคำนวณยอดสะสม การจัดอันดับภายในกลุ่ม และการกรองหลายขั้นตอนที่หากทำใน Pandas จะต้องเขียนโค้ดยืดยาว

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

query = '''
    WITH monthly_revenue AS (
        SELECT strftime('%Y-%m', order_date) AS month,
               SUM(amount) AS revenue
        FROM orders
        WHERE status = 'completed'
        GROUP BY month
    )
    SELECT month,
           revenue,
           revenue - LAG(revenue) OVER (ORDER BY month)
               AS month_over_month_change
    FROM monthly_revenue
    ORDER BY month
'''

df = pd.read_sql_query(query, con=engine)
print(df.tail())

การอ่านข้อมูลพร้อม DatetimeIndex

เมื่ออ่านข้อมูลอนุกรมเวลาจากฐานข้อมูล ให้กำหนดคอลัมน์การประทับเวลาเป็นดัชนีของ DataFrame โดยส่ง index_col='date_column' และ parse_dates=['date_column'] ให้กับ read_sql_query วิธีนี้จะได้ DatetimeIndex โดยตรง ทำให้แบ่งข้อมูลตามเวลาใน Pandas (df['2024-01']) ปรับความถี่ข้อมูล และคำนวณแบบหน้าต่างเลื่อนได้โดยไม่ต้องประมวลผลเพิ่มเติมภายหลัง อาร์กิวเมนต์ parse_dates จะบอกให้ Pandas แปลงคอลัมน์เป็น datetime64

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///metrics.db')

df = pd.read_sql_query(
    'SELECT recorded_at, metric_value FROM daily_metrics ORDER BY recorded_at',
    con=engine,
    index_col='recorded_at',
    parse_dates=['recorded_at']
)
print(df.index.dtype)   # datetime64[ns]
print(df['2024-06'])    # Slice by month directly

การวิเคราะห์ประสิทธิภาพของคำค้นที่ช้า

เมื่อคำสั่งค้นหาทำงานช้า ให้เพิ่มคำสำคัญ SQL EXPLAIN (หรือ EXPLAIN QUERY PLAN ใน SQLite) ไว้ก่อนคำสั่ง SELECT เพื่อดูแผนการทำงานของฐานข้อมูล ให้มองหาการสแกนตารางทั้งหมด ('SCAN TABLE') ในจุดที่ควรเป็นการค้นหาผ่านดัชนี ('SEARCH TABLE') การไม่มีดัชนีในคอลัมน์ที่ใช้กับ WHERE และ JOIN เป็นสาเหตุที่พบบ่อยที่สุดของคำสั่งค้นหาที่ทำงานช้า ให้สร้างดัชนีที่เหมาะสมในฐานข้อมูล แล้วตรวจสอบอีกครั้งด้วย EXPLAIN ก่อนเรียกใช้ pipeline ของ Pandas ใหม่

import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

# Check if the query uses an index
with engine.connect() as conn:
    plan = conn.execute(sa.text(
        'EXPLAIN QUERY PLAN SELECT * FROM orders WHERE customer_id = 42'
    )).fetchall()
    for row in plan:
        print(row)
    # Look for 'SEARCH TABLE orders USING INDEX' — not 'SCAN TABLE'

การแบ่งหน้าเพื่อจัดการชุดผลลัพธ์ขนาดใหญ่

เมื่อต้องวนซ้ำผลลัพธ์ชุดใหญ่แบบโต้ตอบได้ (เช่น ประมวลผลผลลัพธ์ทีละหน้า) ให้ใช้ SQL LIMIT และ OFFSET เพื่อทำ การแบ่งหน้า ดึงข้อมูลครั้งละ N แถว ประมวลผล แล้วจึงดึง N แถวถัดไป แม้ว่าวิธีนี้จะมีประสิทธิภาพน้อยกว่าวิธีใช้ chunksize (ซึ่งจะคงเคอร์เซอร์ไว้) แต่การแบ่งหน้าก็มีประโยชน์เมื่อต้องแสดงแถวข้อมูลทีละส่วนในรายงาน หรือเมื่อต้องรวมผลลัพธ์จากคำสั่งค้นหาหลายรายการ

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')
page_size = 10000
offset = 0

while True:
    query = sa.text(
        'SELECT * FROM orders ORDER BY order_id LIMIT :limit OFFSET :offset'
    )
    with engine.connect() as conn:
        df = pd.read_sql_query(query, con=conn,
                               params={'limit': page_size, 'offset': offset})
    if len(df) == 0:
        break
    print(f'Page at offset {offset}: {len(df)} rows')
    offset += page_size

การรวมคำสั่งค้นหา SQL เข้ากับตรรกะของ Pandas

รูปแบบที่ทรงพลังที่สุดคือ pipeline แบบผสม: ใช้ SQL สำหรับการกรองและการรวมข้อมูลในระดับภาพรวม จากนั้นใช้ Pandas สำหรับการแปลงข้อมูลในรายละเอียดที่ SQL เขียนได้ไม่สะดวก (ตารางพิวอต การแยกวิเคราะห์สตริง ฟังก์ชัน apply และหน้าต่างแบบเลื่อน) อ่านชุดผลลัพธ์จาก SQL ที่มีขนาดจัดการได้ (หลักพันแถว) แล้วเรียกใช้การดำเนินการของ Pandas ต่อเนื่องกับ DataFrame ที่ได้ วิธีนี้รวมจุดแข็งของเครื่องมือทั้งสองไว้ด้วยกัน พร้อมทำให้ข้อมูลไหลผ่านกระบวนการ Python เดียว

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

# SQL: coarse filter and join
df = pd.read_sql_query('''
    SELECT o.customer_id, o.amount, o.order_date, c.country
    FROM orders o JOIN customers c ON o.customer_id = c.id
    WHERE o.status = 'completed'
''', con=engine, parse_dates=['order_date'])

# Pandas: rolling 30-day revenue per country
df = df.sort_values('order_date')
df['rolling_30d'] = (
    df.groupby('country')['amount']
    .transform(lambda x: x.rolling('30D').sum())
)
print(df.head())

การจัดการข้อผิดพลาดสำหรับคำสั่งค้นหาฐานข้อมูล

คำสั่งค้นหาฐานข้อมูลอาจล้มเหลวเนื่องจากหมดเวลาการเชื่อมต่อเครือข่าย ข้อผิดพลาดทางไวยากรณ์ หรือการเชื่อมต่อหลุด ให้ครอบการเรียกใช้ฐานข้อมูลด้วยบล็อก try-except ที่ดักจับ sqlalchemy.exc.OperationalError สำหรับปัญหาการเชื่อมต่อ และ sqlalchemy.exc.ProgrammingError สำหรับข้อผิดพลาดทางไวยากรณ์ของ SQL ให้บันทึกข้อผิดพลาดพร้อมบริบท (คำสั่งค้นหาและพารามิเตอร์) แล้วลองใหม่โดยเพิ่มช่วงเวลารอแบบทวีคูณ หรือยุติการทำงานอย่างเหมาะสม ใน pipeline สำหรับใช้งานจริง การแยกข้อผิดพลาดชั่วคราว (ที่ลองใหม่ได้) ออกจากข้อผิดพลาดถาวร (ต้องแก้ SQL) เป็นสิ่งจำเป็น

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///sales.db')

try:
    df = pd.read_sql_query(
        'SELECT * FROM nonexistent_table',
        con=engine
    )
except sa.exc.OperationalError as e:
    print(f'Connection or table error: {e}')
except sa.exc.ProgrammingError as e:
    print(f'SQL syntax error: {e}')
except Exception as e:
    print(f'Unexpected error: {type(e).__name__}: {e}')

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจแนวคิดด้านการวิเคราะห์ข้อมูลจากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า pd.read_sql_query() ใช้ดำเนินการกับ SQL SELECT ใด ๆ และส่งคืน DataFrame, การส่งตัวกรองและการรวมข้อมูลไปให้ SQL จัดการ มีประสิทธิภาพมากกว่าการโหลดตารางทั้งหมดเข้าสู่ Pandas และ pipeline แบบผสม จะใช้ SQL เพื่อลดขนาดข้อมูลในระดับภาพรวม แล้วใช้ Pandas สำหรับการแปลงข้อมูลแบบกำหนดเองในรายละเอียด บทถัดไป เราจะเรียนรู้วิธีเขียน DataFrame กลับลงในตารางฐานข้อมูล

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การเรียกใช้คำสั่ง SQL จาก Pandas” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเรียกใช้คำสั่ง SQL จาก Pandas” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเรียกใช้คำสั่ง SQL จาก Pandas”

ดำเนินการคำสั่ง SELECT ใด ๆ ด้วย pd.read_sql_query และกำหนดพารามิเตอร์ให้คำสั่งอย่างปลอดภัยเพื่อป้องกัน SQL injection คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การเรียกใช้คำสั่ง SQL จาก Pandas” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม

ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเชื่อมต่อฐานข้อมูลด้วย SQLAlchemy
  2. การเรียกใช้คำสั่ง SQL จาก Pandas
  3. การเขียน DataFrames ลงในตารางฐานข้อมูล
  4. Pandas เทียบกับ SQL: การเลือกเครื่องมือที่เหมาะสม
← กลับไปที่ Pandas & NumPy Academy