Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 137 additions & 69 deletions iotdb-client/client-py/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,93 +413,161 @@ cursor.close()
conn.close()
```

### IoTDB SQLAlchemy Dialect (Experimental)
The SQLAlchemy dialect of IoTDB is written to adapt to Apache Superset.
This part is still being improved.
Please do not use it in the production environment!
#### Mapping of the metadata
The data model used by SQLAlchemy is a relational data model, which describes the relationships between different entities through tables.
While the data model of IoTDB is a hierarchical data model, which organizes the data through a tree structure.
In order to adapt IoTDB to the dialect of SQLAlchemy, the original data model in IoTDB needs to be reorganized.
Converting the data model of IoTDB into the data model of SQLAlchemy.

The metadata in the IoTDB are:

1. Database
2. Path
3. Entity
4. Measurement

The metadata in the SQLAlchemy are:
1. Schema
2. Table
3. Column

The mapping relationship between them is:

| The metadata in the SQLAlchemy | The metadata in the IoTDB |
| -------------------- | ---------------------------------------------- |
| Schema | Database |
| Table | Path ( from database to entity ) + Entity |
| Column | Measurement |

The following figure shows the relationship between the two more intuitively:

![sqlalchemy-to-iotdb](https://github.com/apache/iotdb-bin-resources/blob/main/docs/UserGuide/API/IoTDB-SQLAlchemy/sqlalchemy-to-iotdb.png?raw=true)

#### Data type mapping
| data type in IoTDB | data type in SQLAlchemy |
|--------------------|-------------------------|
| BOOLEAN | Boolean |
| INT32 | Integer |
| INT64 | BigInteger |
| FLOAT | Float |
| DOUBLE | Float |
| TEXT | Text |
| LONG | BigInteger |
#### Example

+ execute statement
### IoTDB SQLAlchemy Dialect

The IoTDB SQLAlchemy dialect provides a standard SQLAlchemy interface for IoTDB's **table model** (IoTDB 2.0+).
It supports DDL (CREATE/DROP TABLE), DML (INSERT/SELECT/DELETE), and schema reflection.
A complete runnable example is available at: [SQLAlchemy Example](https://github.com/apache/iotdb/blob/master/iotdb-client/client-py/sqlalchemy_example.py)

#### Prerequisites

```bash
pip install apache-iotdb sqlalchemy
```

#### Connection URL

```
iotdb://username:password@host:port/database
```

The `/database` part is optional. If omitted, you can specify the database using `schema=` on tables or via `USE` statements.

```python
from sqlalchemy import create_engine

engine = create_engine("iotdb://root:root@127.0.0.1:6667")
connect = engine.connect()
result = connect.execute("SELECT ** FROM root")
for row in result.fetchall():
print(row)
```

+ ORM (now only simple queries are supported)
#### Metadata Mapping

| SQLAlchemy | IoTDB |
|------------|----------|
| Schema | Database |
| Table | Table |
| Column | Column |

#### Column Categories

IoTDB table model columns have categories that must be specified via the `iotdb_category` dialect option:

| Category | Description |
|-------------|------------------------------------------------------|
| `TIME` | Timestamp column (auto-generated if not specified) |
| `TAG` | Identifier/indexing columns (e.g., region, device) |
| `ATTRIBUTE` | Descriptive columns (e.g., model, firmware version) |
| `FIELD` | Measurement/metric columns (e.g., temperature) |

#### Data Type Mapping

| IoTDB | SQLAlchemy |
|-----------|--------------|
| BOOLEAN | Boolean |
| INT32 | Integer |
| INT64 | BigInteger |
| FLOAT | Float |
| DOUBLE | Float |
| STRING | String |
| TEXT | Text |
| BLOB | LargeBinary |
| TIMESTAMP | DateTime |
| DATE | Date |

#### DDL — Create Table

Use `iotdb_category` on each column and `iotdb_ttl` on the table:

```python
from sqlalchemy import create_engine, Column, Float, BigInteger, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Table, Column, Float, String, Boolean, MetaData

metadata = MetaData()
sensors = Table(
"sensors",
metadata,
Column("region", String, iotdb_category="TAG"),
Column("device_id", String, iotdb_category="TAG"),
Column("model", String, iotdb_category="ATTRIBUTE"),
Column("temperature", Float, iotdb_category="FIELD"),
Column("humidity", Float, iotdb_category="FIELD"),
Column("status", Boolean, iotdb_category="FIELD"),
schema="my_database",
iotdb_ttl=86400000, # TTL in milliseconds (1 day)
)

metadata = MetaData(
schema='root.factory'
metadata.create_all(engine)
```

To define an explicit TIME column instead of using the auto-generated one:

```python
from sqlalchemy import BigInteger

events = Table(
"events",
metadata,
Column("ts", BigInteger, iotdb_category="TIME"),
Column("device_id", String, iotdb_category="TAG"),
Column("value", Float, iotdb_category="FIELD"),
schema="my_database",
)
Base = declarative_base(metadata=metadata)
```

#### DML — Insert, Query, Delete

class Device(Base):
__tablename__ = "room2.device1"
Time = Column(BigInteger, primary_key=True)
temperature = Column(Float)
status = Column(Float)
```python
with engine.connect() as conn:
# Insert
conn.execute(
sensors.insert().values(
region="asia", device_id="d001", temperature=25.5, humidity=60.0, status=True,
)
)

# Select all
result = conn.execute(sensors.select())
for row in result:
print(row)

engine = create_engine("iotdb://root:root@127.0.0.1:6667")
# Select with WHERE, ORDER BY, LIMIT
result = conn.execute(
sensors.select()
.where(sensors.c.region == "asia")
.order_by(sensors.c.temperature)
.limit(10)
)

DbSession = sessionmaker(bind=engine)
session = DbSession()
# Delete
conn.execute(sensors.delete().where(sensors.c.device_id == "d001"))
```

res = session.query(Device.status).filter(Device.temperature > 1)
#### Schema Reflection

for row in res:
print(row)
```python
from sqlalchemy import inspect

insp = inspect(engine)

# List databases
schemas = insp.get_schema_names()

# List tables in a database
tables = insp.get_table_names(schema="my_database")

# Get column details
columns = insp.get_columns(table_name="sensors", schema="my_database")
for col in columns:
print(col["name"], col["type"], col.get("iotdb_category"))
```

#### Raw SQL

```python
from sqlalchemy.sql import text

with engine.connect() as conn:
result = conn.execute(text("SELECT * FROM my_database.sensors"))
for row in result:
print(row)
```


Expand Down
Loading
Loading