# SQLite में पैरामीटरयुक्त CRUD कैसे करें

> पोज़िशनल पैरामीटर और cursor के साथ डालें, पढ़ें, अपडेट करें और मिटाएँ, बिना SQL को जोड़े।

Source: https://crossfly.dev/hi/docs/cookbook/data/crud — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# SQLite में पैरामीटरयुक्त CRUD कैसे करें

**उद्देश्य.** INSERT/UPDATE/DELETE और SELECT को **पोज़िशनल पैरामीटर** (`?`) के साथ निष्पादित करना, स्ट्रिंग जोड़ने (जो SQL injection और उद्धरण चिह्न त्रुटियाँ पैदा करता है) से बचते हुए। CrossFly की दो इंडेक्स परंपराओं पर ध्यान दें।

> ⚠️ **इंडेक्स.** पैरामीटरों को **bind** करते समय, इंडेक्स **1-based** होते हैं (`?` नं. 1, 2, ...)। cursor से कॉलम **पढ़ते** समय, इंडेक्स **0-based** होते हैं (`getString(0)` = पहला कॉलम)। यह जानबूझकर है और SQLite के नेटिव API को प्रतिबिंबित करता है।

## उपयोग किए गए APIs
- `SqliteDb.execute(String sql, Object... params)` — तैयार करता है, `bindAll(params)` करता है (bind **1-based**), एक एकल INSERT/UPDATE/DELETE निष्पादित करता है और **प्रभावित पंक्तियों की संख्या** (`int`) लौटाता है। प्रकार अनुमानित किए जाते हैं: `Integer/Long/Short/Byte`→पूर्णांक, `Float/Double`→वास्तविक, `Boolean`→0/1, `byte[]`→BLOB, `null`→NULL, अन्यथा `toString()`→TEXT।
- `SqliteDb.query(String sql, Object... params)` — एक **खुला** `SqliteCursor` लौटाता है (bind 1-based)। कॉलर को इसे **बंद करना चाहिए** (`try-with-resources` उपयोग करें)।
- `SqliteCursor.next()` — अगली पंक्ति पर आगे बढ़ता है; यदि पंक्ति हो तो `true` लौटाता है।
- `SqliteCursor.getInt(col)/getLong/getDouble/getString/getBlob/isNull(col)` — टाइप किए गए getters, कॉलम **0-based**।
- `SqliteDb.queryLong(sql, defaultValue, params)` — शॉर्टकट: पहली पंक्ति का पहला कॉलम `long` के रूप में, या यदि कोई पंक्ति न हो तो `defaultValue`।
- `SqliteDb.queryString(sql, params)` — शॉर्टकट: पहली पंक्ति का पहला कॉलम `String` के रूप में, या यदि कोई पंक्ति न हो तो `null`।
- `SqliteDb.lastInsertRowid()` — अंतिम INSERT का rowid (`long`)। `SqliteDb.changes()` — अंतिम निर्देश द्वारा बदली गई पंक्तियाँ।

## पूरा उदाहरण (कॉपी करें, पेस्ट करें और चलाएँ)

```java
package com.exemplo;

import dev.crossfly.ui.*;                     // Window
import dev.crossfly.ui.layout.*;             // VerticalLayout
import dev.crossfly.sqlite.*;                // SqliteDb, SqliteCursor

/** चलाने योग्य मुख्य स्क्रीन। launcher (classname) की ओर संकेत करें और चलाएँ: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      try (SqliteDb db = SqliteDb.open("app.db"))
      {
         db.exec("CREATE TABLE IF NOT EXISTS person(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

         // CREATE — स्थितीय पैरामीटर (? क्रमांक 1 = name, ? क्रमांक 2 = age)
         int inserted = db.execute("INSERT INTO person(name, age) VALUES(?, ?)", "Alice", 30);
         long id = db.lastInsertRowid();            // उत्पन्न rowid
         System.out.println(inserted + " linha(s), id=" + id);

         // READ — cursor: कॉलम 0-based
         try (SqliteCursor c = db.query("SELECT name, age FROM person WHERE age > ?", 18))
         {
            while (c.next())
               System.out.println(c.getString(0) + " = " + c.getInt(1));   // col 0 = name, col 1 = age
         }

         // READ scalar — शॉर्टकट
         long total = db.queryLong("SELECT count(*) FROM person", 0);
         String nome = db.queryString("SELECT name FROM person WHERE id = ?", id);

         // UPDATE — प्रभावित पंक्तियों की संख्या लौटाता है
         int updated = db.execute("UPDATE person SET age = ? WHERE id = ?", 31, id);

         // DELETE
         int deleted = db.execute("DELETE FROM person WHERE id = ?", id);
      }
   }
}
```

> नीचे दिया गया अंश **केवल मुख्य भाग** दिखाता है। इसे चलाने के लिए, इसे ऊपर दिए गए `MainWindow` कंकाल में रखें।

## न्यूनतम अंश
```java
// स्रोत में सत्यापित: execute (bind 1-based), query + cursor (getters 0-based), queryLong/queryString
import dev.crossfly.sqlite.*;

try (SqliteDb db = SqliteDb.open("app.db"))
{
   db.exec("CREATE TABLE IF NOT EXISTS person(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

   // CREATE — स्थितीय पैरामीटर (? क्रमांक 1 = name, ? क्रमांक 2 = age)
   int inserted = db.execute("INSERT INTO person(name, age) VALUES(?, ?)", "Alice", 30);
   long id = db.lastInsertRowid();            // उत्पन्न rowid
   System.out.println(inserted + " linha(s), id=" + id);

   // READ — cursor: कॉलम 0-based
   try (SqliteCursor c = db.query("SELECT name, age FROM person WHERE age > ?", 18))
   {
      while (c.next())
         System.out.println(c.getString(0) + " = " + c.getInt(1));   // col 0 = name, col 1 = age
   }

   // READ scalar — शॉर्टकट
   long total = db.queryLong("SELECT count(*) FROM person", 0);
   String nome = db.queryString("SELECT name FROM person WHERE id = ?", id);

   // UPDATE — प्रभावित पंक्तियों की संख्या लौटाता है
   int updated = db.execute("UPDATE person SET age = ? WHERE id = ?", 31, id);

   // DELETE
   int deleted = db.execute("DELETE FROM person WHERE id = ?", id);
}
```

## और गहराई से जानें
- [SQLite storage गाइड](/docs/data-and-services/storage-sqlite) · विकास गाइड
- संबंधित रेसिपी: [डेटाबेस खोलना/बनाना](/docs/cookbook/data/abrir-banco) · [ट्रांज़ैक्शन और बल्क लेखन](/docs/cookbook/data/transacao-e-bulk) · [paint thread के बाहर उपयोग](/docs/cookbook/data/banco-fora-da-paint-thread)
