I'm trying to update the field buyPrice in all the products that match a query, what is the correct syntax for this?
I'm getting this error
An error occurred while running the statement: sub-select returns 22 columns - expected 1
(code 1 SQLITE_ERROR): , while compiling: UPDATE product set buyPrice = ? in
(SELECT * FROM product p JOIN roomuser u ON p.businessId = u.currentBusinessId WHERE sellPrice 10
This is my query so far:
#Query("""
UPDATE product
set buyPrice = :newPrice in
(SELECT * FROM
product p JOIN user u ON p.businessId = u.currentBusinessId
WHERE sellPrice < 10)
""")
suspend fun updateProduct(newPrice: Float)
I think that you want to use a WHERE clause in your UPDATE statement, which may be something like this:
UPDATE product
SET buyPrice = :newPrice
WHERE product_id IN (
SELECT p.product_id
FROM product p JOIN user u
ON p.businessId = u.currentBusinessId
WHERE sellPrice < 10
)
I use product_id in my code which I assume is the primary key of the table product.
Or, if sellPrice is a column of the table product, you could use EXISTS instead of the join like this:
UPDATE product
SET buyPrice = :newPrice
WHERE sellPrice < 10
AND EXISTS (SELECT 1 FROM user u WHERE u.currentBusinessId = product.businessId)
I have an application that makes quite a lot of selects, listing its results and allowing the user edit certain values.
The core of my question is if its possible to improve my queries or not given the following query in SQLite:
"SELECT X.data1, X.data2, count(X.id_X) as Quantity_Itens,
(select count(*) from Table2 where id_X=X.id_X) local_Table2,
(select count(*) from Table3 inner join Table2 on Table3.id_Table2 = Table2.id where Table3.id_X=X.id_X and type=1) Quantity_Type1,
(select count(*) from Table3 inner join Table2 on Table3.id_Table2 = Table2.id where Table3.id_X=X.id_X and type=2) Quantity_Type2,
(select count(*) from Table4 where id_X = X.id_X) Quantity_Other,
(select count(*) from Table2 where id_X = X.id_X and status <10) Total_Data FROM Table1 X where (X.type_item = 2 or X.type_item = 4 or X.type_item = 6 or X.type_item = 8) and X.ative = 1 and id_local != 0 group by X.id_X order by X.Alias1"
I am not sure if using promisses will improve in any way this, as I need all those datas before allowing the user to take control again.
Also, may or may not be relevant:
OS: Android 4+
Frameworks: Ionic1, AngularJS, Cordova
In your query there are 5 subqueries executed for each of the rows of Table1.
Only one of them accesses only once 1 table.
2 of them access the same table twice and 2 of them access 2 joined tables twice.
This means there are multiple scans through the same tables for each of the rows of Table1.
Also you are aggregating inside Table1, with GROUP BY id_X, but you have in the SELECT list 2 columns: data1 and data2, which are not included in the GROUP BY clause. This means that the returned values of these columns are arbitrary.
And what is that column Alias1? There is no such column among the returned columns of the query.
Anyway, I suggest that you aggregate first in each table, or join of tables and then join to Table1.
Like this:
SELECT t1.data1,
t1.data2,
t1.Quantity_Items,
t2.local_Table2,
t3.Quantity_Type1,
t3.Quantity_Type2,
t4.Quantity_Other,
t2.Total_Data
FROM (
-- The values returned for data1, data2 and Alias1 will be arbitrary
SELECT id_X, data1, data2, Alias1, COUNT(*) Quantity_Items
FROM table1
GROUP BY id_X
) t1
INNER JOIN (
SELECT id_X, COUNT(*) local_Table2, SUM(status < 10) Total_Data
FROM Table2
GROUP BY id_X
) t2 ON t2.id_X = t1.id_X
INNER JOIN (
SELECT t3.id_X, SUM(type = 1) Quantity_Type1, SUM(type = 2) Quantity_Type2
FROM Table3 t3 INNER JOIN Table2 t2
ON t3.id_Table2 = t2.id
GROUP BY t3.id_X
) t3 ON t3.id_X = t1.id_X
INNER JOIN (
SELECT id_X, COUNT(*) Quantity_Other
FROM Table4
GROUP BY id_X
) t4 ON t4.id_X = t1.id_X
WHERE t1.type_item IN (2, 4, 6, 8)
AND t1.active = 1 AND t1.id_local <> 0
ORDER BY t1.Alias1
I am building my first android app where I am trying to sync mysql data to sqlite in android. I have two tables in mysql and both gets synced properly into android sqlite. The first table is as follows:
id ProjectName
1 RA_Tesco
2 RA_Coors
3 RA_JWNT
The second table is as follows:
id pid Outlet Add1
1 1 Tesco XYZ
2 1 Tesco ABC
3 2 Coors NBC
The PID in second table references to id of first table. How can I subset the second table based on PID value derived from id of first table. I know it is pretty straight forward in php or mysql or even in Python or R. However, fetching the id based on string and referencing the same in the second table seems quite tricky in Android. My codes so far:
sqLiteDatabase = sqLiteHelper.getWritableDatabase();
clickedId = getIntent().getExtras().get("clickedId").toString();
When I toast clickedId, I get the correct string, for example, RA_Tesco.
cursor = sqLiteDatabase.rawQuery("SELECT * FROM "+SQLiteHelper.TABLE_NAME1+" where pid = 1"+"", null);
The above code also renders the correct set of records from the sqlite table. I am struggling with integrating them both. I tried the following:
String pid;
sqLiteDatabase = sqLiteHelper.getWritableDatabase();
clickedId = getIntent().getExtras().get("clickedId").toString();
pid = sqLiteDatabase.rawQuery( "select id from "+sqLiteHelper.TABLE_NAME+" where projectName = "+clickedId+"", null );
I am getting incompatible types error.
This is what worked for me:
clickedId = getIntent().getExtras().get("clickedId").toString();
cursor = sqLiteDatabase.rawQuery("SELECT * FROM "+SQLiteHelper.TABLE_NAME1+" where pid = (select id from "+SQLiteHelper.TABLE_NAME+ " where ProjectName = '"+clickedId+"'"+")", null);
I just followed the same MySQL principle of nesting queries. The above code roughly reads as follows:
select * from table2 where pid = (select id from table1 where projectname="xyz");
1) Try put your query to single quote
2) rawQuery returns Cursor, not String
So,
Cursor pidCursor = sqLiteDatabase.rawQuery( "select id from "+sqLiteHelper.TABLE_NAME+" where projectName = '"+clickedId+"'", null );
If you want to get the corresponding rows from the 2nd table when you pass as an argumnent the value of a ProjectName (I guess this is clickedId although its name is id?), create a statement like this:
String sql =
"select t2.* from " + SQLiteHelper.TABLE_NAME1 +
" t2 inner join " + SQLiteHelper.TABLE_NAME +
" t1 on t1.id = t2.pid where t1.ProjectName = ?";
This joins the 2 tables and returns all the columns of the 2nd table.
The execute rawQuery() by passing clickedId as a parameter, which is the proper way to avoid sql injection:
Cursor cursor = sqLiteDatabase.rawQuery(sql, new String[] {clickedId});
I have 4 tables:
tasks table
(task_id , department_id , task_title , task_description , task_start_date , task_due_date , task_rating , task_is_completed)
employees table
(employee_id , department_id , employee_name , employee_salary , employee_hire_date)
departments table
(department_id , department_name)
employees_tasks join table
(employee_id , task_id)
Each table is an entity in room database.
I want to return 2 extra columns with the (select * from employees)
one is for calculating employee's rating (by getting average of task_rating column in tasks table the tasks must be completed) the other column is to show the number of tasks running for that employee (by getting count of rows in tasks with task_is_completed = 0 )
I don't know which table to join with which table. we managed to make two separate SQL statements that return those 2 columns by using union and left joins but they are pretty ugly and when combining them it doesn't work.
what we have tried
select employees.employee_name , employees.employee_id ,avg(tasks.task_rating) as Ratings from employees , tasks inner join employees_tasks on(employees.employee_id = employees_tasks.employee_id )AND tasks.task_id = employees_tasks.task_id where tasks.task_is_completed = 1 group by (employees.employee_name )
union select employees.employee_name, employees.employee_id, avg(0) as Ratings from employees where employees.employee_id not in (select employees.employee_id from employees , tasks inner join employees_tasks on(employees.employee_id = employees_tasks.employee_id ) AND tasks.task_id = employees_tasks.task_id where tasks.task_is_completed = 1 group by (employees.employee_name ) ) group by employees.employee_id order by employees.employee_id ;
select employees.employee_name , employees.employee_id ,count(tasks.task_title) as tasks_Running from employees , tasks inner join employees_tasks on(employees.employee_id = employees_tasks.employee_id )AND tasks.task_id = employees_tasks.task_id where tasks.task_is_completed = 0 group by (employees.employee_name )
union select employees.employee_name , employees.employee_id ,0 as tasks_Running from employees where (employees.employee_id not in (select employees.employee_id from employees , tasks inner join employees_tasks on(employees.employee_id = employees_tasks.employee_id )AND tasks.task_id = employees_tasks.task_id where tasks.task_is_completed = 0 group by (employees.employee_name )))group by (employees.employee_name) order by employees.employee_id ;
We want the output to be like this
(employee_id , department_id , employee_name , employee_salary , employee_hire_date , ratings , numTasksRunning)
I believe the following may suit :-
WITH
-- Common Table Expression 1 - Average of Completed Tasks per employee
employee_completedtask_info AS (
SELECT employees.employee_id,avg(tasks.task_rating) AS atr
FROM employees_tasks
JOIN tasks ON employees_tasks.task_id = tasks.task_id
JOIN employees ON employees_tasks.employee_id = employees.employee_id
WHERE tasks.task_is_completed > 0
GROUP BY employees.employee_id
),
-- Common Table Expression 2 - Incompleted Taks per employee
employee_notcompleted_info AS (
SELECT employees.employee_id,count() AS itc
FROM employees_tasks
JOIN tasks ON employees_tasks.task_id = tasks.task_id
JOIN employees ON employees_tasks.employee_id = employees.employee_id
WHERE tasks.task_is_completed = 0
GROUP BY employees.employee_id
),
-- Common Table Expression 3 - Total Tasks per Employee
employee_total_tasks AS (
SELECT employees.employee_id,count() AS ttc
FROM employees_tasks
JOIN tasks ON employees_tasks.task_id = tasks.task_id
JOIN employees ON employees_tasks.employee_id = employees.employee_id
GROUP BY employees.employee_id
)
SELECT employees.employee_name,
CASE WHEN atr IS NOT NULL THEN atr ELSE 0 END AS average_completed_task_rating,
CASE WHEN itc IS NOT NULL THEN itc ELSE 0 END AS incomplete_task_count,
CASE WHEN ttc IS NOT NULL THEN ttc ELSE 0 END AS total_task_count
FROM employees
LEFT JOIN employee_completedtask_info ON employees.employee_id = employee_completedtask_info.employee_id
LEFT JOIN employee_notcompleted_info ON employees.employee_id = employee_notcompleted_info.employee_id
LEFT JOIN employee_total_tasks ON employees.employee_id = employee_total_tasks.employee_id
;
based upon data generated as per the following :-
DROP TABLE IF EXISTS employees;
CREATE TABLE IF NOT EXISTS employees (employee_id INTEGER PRIMARY KEY, department_id INTEGER, employee_name TEXT, employee_salary REAL, employee_hire_date TEXT);
DROP TABLE IF EXISTS departments;
CREATE TABLE IF NOT EXISTS departments (department_id INTEGER PRIMARY KEY, department_name TEXT);
DROP TABLE IF EXISTS employees_tasks;
CREATE TABLE IF NOT EXISTS employees_tasks (employee_id INTEGER, task_id INTEGER, PRIMARY KEY(employee_id, task_id));
INSERT INTO departments VALUES
(null,'Maths'),(null,'English'),(null,'Craft')
;
INSERT INTO employees VALUES
(null,1,'Fred',55000,'2000-01-02'),
(null,2,'Mary',62000,'1996-03-20'),
(null,3,'Tom',52000,'2004-10-11'),
(null,3,'Susan',72000,'1999-06-14'),
(null,2,'Bert',66000,'2000-10-15'),
(null,1,'Jane',70000,'1992-04-02')
;
INSERT INTO tasks VALUES
(null,3,'Task 001 - Craft','Do the Craft thinggy','2018-01-01','2018-08-19',10,0),
(null,1,'Task 002 - Maths','Do the Maths thinggy','2018-03-14','2019-03-13',20,0),
(null,2,'Task 003 - English','Do the English thinggy','2018-02-14','2018-09-14',8,0),
(null,3,'Task 004 - Craft','Do the Craft job','2018-01-01','2018-08-19',10,1),
(null,1,'Task 005 - Maths','Do the Maths job','2018-03-14','2019-03-13',20,1),
(null,2,'Task 006 - English','Do the English job','2018-02-14','2018-09-14',8,1),
(null,3,'Task 007 - Craft','Craft thinggy','2018-03-03','2018-11-21',10,0),
(null,1,'Task 008 - Maths','Maths thinggy','2018-03-14','2019-03-13',20,0),
(null,2,'Task 009 - English','English thinggy','2018-02-14','2018-09-14',8,0)
;
INSERT INTO employees_tasks VALUES
(1,2),(1,5),(1,8),(1,6),
(2,2),
(3,1),(3,4),(3,7)
;
This results in :-
Note This converts null entries to 0's (i.e. in the above there are no tasks for Susan, Bert and Jane so nulls for their task counts/averages, which complicates matters a little hence the CASE WHEN ... THEN ... ELSE .... END AS clauses).
Note I've included the total tasks counts as this may be useful/wanted (the third CTE extracts this info)
I have the following tables in an sqlite database:
items
______
_id (PK)
name
section_subsection_id (FK)
section_subsections
______
_id (PK)
section_id (FK)
subsection_id (FK)
subsections
______
_id (PK)
name
sections
______
_id (PK)
name
I would like to provide a certain keyword to subsections that would only grab only those that match this keyword under a limit, say x, and count all the items under this section AND subsection match.
I have used several queries, here is one:
String selectQuery = "Select subsections.name, subsections._id, temp.count as count
FROM subsections LEFT JOIN
sections_subsections ON subsections._id = sections_subsections.subsection_id
JOIN items (SELECT count(items._id) as count from items) temp
ON items.section_subsection_id = sections_subsections._id
WHERE subsections.name LIKE 'keyword' AND sections_subsections.section_id = 1 ORDER BY
subsections.name ASC LIMIT 50 OFFSET 0 ";
When I try to iterate through the results, I get the list matching the keyword search but the count always displays the last count value from the result set. When I run the raw query in sqlite shell, I see the correct counts in the column with the respective rows, but iterating through the cursor in Android/Java seems to have a problem. Or possibly my query?
So for ListView in the app I would get same counts (that is all 20s), but in shell I see count with correct value. In fact, during cursor iteration, if I Log.d count to the screen it is also all 20s, yet the other column value name is different. What is wrong with my query? Or how do I correctly iterate through a table with multiple joins?
_id name count
---------------
1 item1 79
2 item2 30
3 item3 20
EDIT:
I'm doing something like this in Java:
Cursor cursor = sqliteDatabase.rawQuery(selectQuery, null);
if (cursor != null) {
cursor.moveToFirst();
}
if (cursor.moveToFirst()) {
do {
SubSection subSection = new SubSection();
subSection.setId(cursor.getInt(cursor.getColumnIndex(KEY_ID))); subSection.setSubSectionName(cursor.getString(cursor.getColumnIndex(KEY_TABLE_SUBSECTIONS_SUBSECTION_NAME)));
subSection.setRecords(cursor.getColumnIndex("count"));
subSections.add(subSection);
}
while
(cursor.moveToNext());
}
try below query
Select subsections.name, subsections._id, (SELECT count(items._id) from items WHERE items.section_subsection_id = sections_subsections._id) as count
FROM subsections LEFT JOIN
sections_subsections ON subsections._id = sections_subsections.subsection_id
WHERE subsections.name LIKE 'keyword' AND sections.name = 'Category' ORDER BY
subsections.name ASC LIMIT 50 OFFSET 0 ";
Thanks Syed Waqas, your answer is correct for joining. The problem was not my queries actually. It was my cursor call. I should have used: cursor.getInt(cursor.getColumnIndex("count")) instead of what I have in my original question. I don't know how I managed to not notice this big mistake. For everyone else, you can debug your cursor with the lovely DatabseUtils. :)
Log.d(LOG, "ROW: " + DatabaseUtils.dumpCursorToString(cursor));