@@ -413,93 +413,161 @@ cursor.close()
413413conn.close()
414414```
415415
416- ### IoTDB SQLAlchemy Dialect (Experimental)
417- The SQLAlchemy dialect of IoTDB is written to adapt to Apache Superset.
418- This part is still being improved.
419- Please do not use it in the production environment!
420- #### Mapping of the metadata
421- The data model used by SQLAlchemy is a relational data model, which describes the relationships between different entities through tables.
422- While the data model of IoTDB is a hierarchical data model, which organizes the data through a tree structure.
423- In order to adapt IoTDB to the dialect of SQLAlchemy, the original data model in IoTDB needs to be reorganized.
424- Converting the data model of IoTDB into the data model of SQLAlchemy.
425-
426- The metadata in the IoTDB are:
427-
428- 1 . Database
429- 2 . Path
430- 3 . Entity
431- 4 . Measurement
432-
433- The metadata in the SQLAlchemy are:
434- 1 . Schema
435- 2 . Table
436- 3 . Column
437-
438- The mapping relationship between them is:
439-
440- | The metadata in the SQLAlchemy | The metadata in the IoTDB |
441- | -------------------- | ---------------------------------------------- |
442- | Schema | Database |
443- | Table | Path ( from database to entity ) + Entity |
444- | Column | Measurement |
445-
446- The following figure shows the relationship between the two more intuitively:
447-
448- ![ sqlalchemy-to-iotdb] ( https://github.com/apache/iotdb-bin-resources/blob/main/docs/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true )
449-
450- #### Data type mapping
451- | data type in IoTDB | data type in SQLAlchemy |
452- | --------------------| -------------------------|
453- | BOOLEAN | Boolean |
454- | INT32 | Integer |
455- | INT64 | BigInteger |
456- | FLOAT | Float |
457- | DOUBLE | Float |
458- | TEXT | Text |
459- | LONG | BigInteger |
460- #### Example
461-
462- + execute statement
416+ ### IoTDB SQLAlchemy Dialect
417+
418+ The IoTDB SQLAlchemy dialect provides a standard SQLAlchemy interface for IoTDB's ** table model** (IoTDB 2.0+).
419+ It supports DDL (CREATE/DROP TABLE), DML (INSERT/SELECT/DELETE), and schema reflection.
420+ A complete runnable example is available at: [ SQLAlchemy Example] ( https://github.com/apache/iotdb/blob/master/iotdb-client/client-py/sqlalchemy_example.py )
421+
422+ #### Prerequisites
423+
424+ ``` bash
425+ pip install apache-iotdb sqlalchemy
426+ ```
427+
428+ #### Connection URL
429+
430+ ```
431+ iotdb://username:password@host:port/database
432+ ```
433+
434+ The ` /database ` part is optional. If omitted, you can specify the database using ` schema= ` on tables or via ` USE ` statements.
463435
464436``` python
465437from sqlalchemy import create_engine
466438
467439engine = create_engine(" iotdb://root:root@127.0.0.1:6667" )
468- connect = engine.connect()
469- result = connect.execute(" SELECT ** FROM root" )
470- for row in result.fetchall():
471- print (row)
472440```
473441
474- + ORM (now only simple queries are supported)
442+ #### Metadata Mapping
443+
444+ | SQLAlchemy | IoTDB |
445+ | ------------| ----------|
446+ | Schema | Database |
447+ | Table | Table |
448+ | Column | Column |
449+
450+ #### Column Categories
451+
452+ IoTDB table model columns have categories that must be specified via the ` iotdb_category ` dialect option:
453+
454+ | Category | Description |
455+ | -------------| ------------------------------------------------------|
456+ | ` TIME ` | Timestamp column (auto-generated if not specified) |
457+ | ` TAG ` | Identifier/indexing columns (e.g., region, device) |
458+ | ` ATTRIBUTE ` | Descriptive columns (e.g., model, firmware version) |
459+ | ` FIELD ` | Measurement/metric columns (e.g., temperature) |
460+
461+ #### Data Type Mapping
462+
463+ | IoTDB | SQLAlchemy |
464+ | -----------| --------------|
465+ | BOOLEAN | Boolean |
466+ | INT32 | Integer |
467+ | INT64 | BigInteger |
468+ | FLOAT | Float |
469+ | DOUBLE | Float |
470+ | STRING | String |
471+ | TEXT | Text |
472+ | BLOB | LargeBinary |
473+ | TIMESTAMP | DateTime |
474+ | DATE | Date |
475+
476+ #### DDL — Create Table
477+
478+ Use ` iotdb_category ` on each column and ` iotdb_ttl ` on the table:
475479
476480``` python
477- from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData
478- from sqlalchemy.ext.declarative import declarative_base
479- from sqlalchemy.orm import sessionmaker
481+ from sqlalchemy import Table, Column, Float, String, Boolean, MetaData
482+
483+ metadata = MetaData()
484+ sensors = Table(
485+ " sensors" ,
486+ metadata,
487+ Column(" region" , String, iotdb_category = " TAG" ),
488+ Column(" device_id" , String, iotdb_category = " TAG" ),
489+ Column(" model" , String, iotdb_category = " ATTRIBUTE" ),
490+ Column(" temperature" , Float, iotdb_category = " FIELD" ),
491+ Column(" humidity" , Float, iotdb_category = " FIELD" ),
492+ Column(" status" , Boolean, iotdb_category = " FIELD" ),
493+ schema = " my_database" ,
494+ iotdb_ttl = 86400000 , # TTL in milliseconds (1 day)
495+ )
480496
481- metadata = MetaData(
482- schema = ' root.factory'
497+ metadata.create_all(engine)
498+ ```
499+
500+ To define an explicit TIME column instead of using the auto-generated one:
501+
502+ ``` python
503+ from sqlalchemy import BigInteger
504+
505+ events = Table(
506+ " events" ,
507+ metadata,
508+ Column(" ts" , BigInteger, iotdb_category = " TIME" ),
509+ Column(" device_id" , String, iotdb_category = " TAG" ),
510+ Column(" value" , Float, iotdb_category = " FIELD" ),
511+ schema = " my_database" ,
483512)
484- Base = declarative_base( metadata = metadata)
513+ ```
485514
515+ #### DML — Insert, Query, Delete
486516
487- class Device (Base ):
488- __tablename__ = " room2.device1"
489- Time = Column(BigInteger, primary_key = True )
490- temperature = Column(Float)
491- status = Column(Float)
517+ ``` python
518+ with engine.connect() as conn:
519+ # Insert
520+ conn.execute(
521+ sensors.insert().values(
522+ region = " asia" , device_id = " d001" , temperature = 25.5 , humidity = 60.0 , status = True ,
523+ )
524+ )
492525
526+ # Select all
527+ result = conn.execute(sensors.select())
528+ for row in result:
529+ print (row)
493530
494- engine = create_engine(" iotdb://root:root@127.0.0.1:6667" )
531+ # Select with WHERE, ORDER BY, LIMIT
532+ result = conn.execute(
533+ sensors.select()
534+ .where(sensors.c.region == " asia" )
535+ .order_by(sensors.c.temperature)
536+ .limit(10 )
537+ )
495538
496- DbSession = sessionmaker(bind = engine)
497- session = DbSession()
539+ # Delete
540+ conn.execute(sensors.delete().where(sensors.c.device_id == " d001" ))
541+ ```
498542
499- res = session.query(Device.status).filter(Device.temperature > 1 )
543+ #### Schema Reflection
500544
501- for row in res:
502- print (row)
545+ ``` python
546+ from sqlalchemy import inspect
547+
548+ insp = inspect(engine)
549+
550+ # List databases
551+ schemas = insp.get_schema_names()
552+
553+ # List tables in a database
554+ tables = insp.get_table_names(schema = " my_database" )
555+
556+ # Get column details
557+ columns = insp.get_columns(table_name = " sensors" , schema = " my_database" )
558+ for col in columns:
559+ print (col[" name" ], col[" type" ], col.get(" iotdb_category" ))
560+ ```
561+
562+ #### Raw SQL
563+
564+ ``` python
565+ from sqlalchemy.sql import text
566+
567+ with engine.connect() as conn:
568+ result = conn.execute(text(" SELECT * FROM my_database.sensors" ))
569+ for row in result:
570+ print (row)
503571```
504572
505573
0 commit comments