2011-04-26 21 views
6

He estado usando SQLite en Android por mucho tiempo, pero es la primera vez que realizo una operación de combinación de tabla. Estoy totalmente frustrado porque he estado trabajando en eso todo el día.SQLite: Cómo unir tablas y presentar el cursor usando SimpleCursorAdapter

Ahora tengo 2 tablas, FTSProfile y FTSCell, y quiero unirlas usando una tecla común A con un LEFT JOIN. Así que implementé una serie de código, ContentProvider y Database para realizar lo que quiero. En la base de datos, utilicé SQLiteQueryBuilder para construir la consulta y obtener el cursor que quiero. Solía:

SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); 
    builder.setTables(FTS_VIRTUAL_TABLE_PROFILE+" LEFT JOIN "+FTS_VIRTUAL_TABLE_CELL+" ON "+FTS_VIRTUAL_TABLE_CELL+"."+Database.KEY_CID+"="+FTS_VIRTUAL_TABLE_PROFILE+"."+Database.KEY_CELL_ID); 
    builder.setProjectionMap(mColumnMap_CombinedTable); 

y mi Hashmap es como:

HashMap<String,String> map = new HashMap<String,String>(); 
     for (String key: KEYS_PROFILE) map.put(key, FTS_VIRTUAL_TABLE_PROFILE+"."+key); 
     for (String key: KEYS_CELL) map.put(key, FTS_VIRTUAL_TABLE_CELL+"."+key); 
     map.put(BaseColumns._ID, BaseColumns._ID); 
     map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 
     map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " + SearchManager.SUGGEST_COLUMN_SHORTCUT_ID); 

Y luego, cuando corro el programa y tratar de abrir la lista para el resultado, me sale un SQLiteException: no such column: _id...

tengo No tengo ideas de cómo resolverlo, pero realmente quiero saber cómo puedo deshacerme de él. ¿Alguien puede ayudar?

Respuesta

6

Ha pregunta divertida. Solo estaba viendo lo mismo hace 30 minutos;). Puede intentar seguir el ejemplo como en la aplicación de contacto nativa de Android.

http://www.google.com/codesearch/p?hl=en#cbQwy62oRIQ/src/com/android/providers/contacts/ContactsProvider2.java&q=ContactsProvider.java&d=5

declaran una interfaz

private interface DataContactsQuery { 
     public static final String TABLE = "data " 
       + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 
       + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 

     public static final String[] PROJECTION = new String[] { 
      RawContactsColumns.CONCRETE_ID, 
      DataColumns.CONCRETE_ID, 
      ContactsColumns.CONCRETE_ID 
     }; 

     public static final int RAW_CONTACT_ID = 0; 
     public static final int DATA_ID = 1; 
     public static final int CONTACT_ID = 2; 
    } 

A continuación, al intentar consultar los resultados que utilizan este trozo de código.

Cursor cursor = null; 
     try { 
      cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 
        mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 
        Contacts.IN_VISIBLE_GROUP + " DESC, " + Data.RAW_CONTACT_ID); 
      if (cursor.moveToFirst()) { 
       dataId = cursor.getLong(DataContactsQuery.DATA_ID); 
       rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 
       contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 
      } else { 
       // No contact found, return a null URI 
       return -1; 
      } 
     } finally { 
      if (cursor != null) { 
       cursor.close(); 
      } 
     } 

¿Le es útil?

+1

pero el problema es que SimpleCursorAdapter requiere un campo "_id" (BaseColumns._ID) para asignar los datos. Entonces, si no declaro ese campo durante la creación de la base de datos, no me permitirían unirme a la mesa. Lo que estoy pensando es, ¿cómo puedo hacer una columna "_id" después de unirme a la tabla utilizando el método que implementé? –

+0

El enlace está muerto. Par de preguntas.¿Cómo obtienes mDB? Parece que no es trivial acceder a la base de datos de contactos ya que no está documentada. ¿Y qué es mSb? – rycfung

+0

mDB es su instancia SQLiteDatabase. mSB es un StringBuilder. Tuve que mirar hacia atrás el código fuente del lanzamiento. –

1

¿Qué tal crear un VIEW en tu base de datos? Si se trata de una consulta frecuente, visualícela como una vista, y puede evitar una gran confusión al configurar la unión, y simplemente preocúpese por los criterios de selección. Si puede escribir la unión como SQL directo, entonces debería poder crear una vista sobre ella y luego usarla.

El problema que veo con su código parece ser que está tratando de seleccionar una columna llamada _id (que es necesaria para un CursorAdapter), pero esa columna no existe. Está mapeando BaseColumns._ID a BaseColumns._ID, pero esas son solo constantes, y si su base de datos no tiene una columna _id, entonces obtendrá el error que está viendo.

CREATE VIEW FooBar AS 
    SELECT Foo.field1 AS FooField1, 
      Foo.field2 AS FooField2, 
      Bar.field1 AS BarField1, 
      Bar.field2 AS BarField2, 
      (Foo._id * 1000000000) + Bar._id AS _id 
    FROM Foo LEFT JOIN Bar ON Foo.Field1 = Bar.Field2; 

Eso (Foo._id * 1000000000) + Bar._id AS _id es una manera rápida y sucia, y probablemente dolorosamente incorrecta de sintetizar una única _id para la fila devuelta por la vista, lo que necesitará si está usando esto como un adaptador. También tiene la desventaja de ser de solo lectura. No puede actualizar un VIEW.

Una vez que tenga su VIEW, puede SELECT contra ella como si fuera una mesa. es decir, SELECT * FROM FooBar WHERE BarField1 > 10;

+0

Gracias por su sugerencia primero =] Pero creo que ahora mi problema es más sobre cómo agregar una columna llamada " _id "en mi tabla de unión. Originalmente en mis 2 tablas, no hay columnas llamadas "_id" y de alguna manera consulto eso en el mapa de proyección, así que incluso si creo la base de datos sin eso, puedo alimentar el cursor al DataAdapter. Sin embargo, después de hacer la unión, el campo _id se ha ido y estoy buscando una manera de volverlo a agregar –

+0

Ok ... Si su fila unida incluye un campo entero que es único en todo el conjunto de resultados, puede usar su mapa de proyección para devolverlo como _id. 'map.put (" myUniqueNumericField ", BaseColumns._ID);' Eso hará que la consulta etiquete esa columna como _id, permitiendo que el CursorAdapter funcione. –

+0

Whups! 'map.put (BaseColumns._ID," myUniqueNumericField ");' Los peligros de publicar desde la memoria ... –

Cuestiones relacionadas