In a table I have the following value:
ID | Exercise1 | Exercise2 | Exercise3
1 | 0 | 0 | 0
2 | 0 | 0 | 0
When a user completes an exercise, the db switches from '0' to '1'. I'm looking for an sql query that searches by the ID number of the user returns the lowest column name that is set to 0.
EX:
ID | Exercise1 | Exercise2 | Exercise3
1 | 1 | 1 | 0
Here the query would return with exercise3, since exercise1 and exercise2 have previously been updated and completed by the user.
I found
SELECT COLUMN_NAME FROM information_schema.columns
but can't put it together with the sorting I'm looking for, any help would be deeply appreciated.
If you have only a handful of exercises (e.g. < 5), then you can simply hardcode the query with a series of nested IF() statements.
If you have more than that, then you should change your data model so each user/exercise mapping is stored in a separate row.
Something like this?
SELECT CASE
WHEN Exercise1=0 THEN 'Exercise1'
WHEN Exercise2=0 THEN 'Exercise2'
WHEN Exercise3=0 THEN 'Exercise3'
ELSE NULL
END AS Exercise
FROM MyTable
WHERE ID = SomeID
Hmmm... you have problems because your design is wrong. The problem is that your database design was affected by how you imagine the presentation of the table. But the database thinking is different. The database would be normally designed this way:
StudentID | ExcerciseID | Completed
1 | 1 | 1
1 | 2 | 1
1 | 3 | 0
2 | 1 | 0
....
And then you can do:
select StudentID, min(ExcerciseID) as FirstExcerciseNotCompleted
from Excercises
where Completed = 0
to see first incomplete excercise for each student, or if you want set next completed excercise to Student 1, just do:
update Excercises
set Completed = 1
where Student = 1 and ExcerciseID = (select min(ExcerciseID) from Excercises where StudentID = 1 and Completed = 0)
Related
I was wondering if it is possible to get the count of a query, plus check if a entity within the query exists at the same time.
So I was looking to do something like this
SELECT
COUNT(a.*)
CASE WHEN ? IN (a.column) THEN 1 ELSE 0 END AS exist
FROM a
WHERE ...
I know I could do a sub-query in the CASE, but is it possible to do it with just the data from the initial query?
EDIT
ie
+------------+
| id column |
+------------+
| 1 5 |
| 2 6 |
| 3 7 |
| 4 8 |
SELECT
COUNT(a.*)
CASE WHEN 7 IN (a.column) THEN 1 ELSE 0 END AS exist
FROM a
WHERE id > 1
Would return
+--------------------+
| COUNT(*) exist |
+--------------------+
| 3 1 |
Because there are 3 entries with an id > 1 and within the entries and there is an entry with column = 7
If you want to check if a value exists in the column, you can do:
SELECT COUNT(*),
MAX(? = a.column) as value_exists
FROM a
WHERE ...
In a numeric context, MySQL treats booleans as integers, with 1 for true and 0 for false. Hence, this returns true if the value is in any row in the column. You can use MIN() if you want to check if the same value is in all the rows.
I try to merge two tables together and want to get a single table with SQL. My main problem is to overwrite existing values, because in the 2nd table (deltaTable) are some new revision rows, that have the same ID as in the first table (rootTable).
Example:
1) rootTable
ID | REV | NAME
1 | 0 | Part 1
2 | 0 | Part 2
3 | 0 | Part 3
4 | 0 | Part 4
5 | 0 | Part 5
2) deltaTable
ID | REV | NAME
2 | 1 | Part 2
4 | 2 | New Part 4
I want to have the following result:
ID | REV | NAME
1 | 0 | Part 1
2 | 1 | Part 2
3 | 0 | Part 3
4 | 2 | New Part 4
5 | 0 | Part 5
Can anyone help me or give me an hint how to manage the SQL code?
If I understand your question correctly, you could use an UPDATE query:
update
rootTable r inner join deltaTable d
on r.id = d.id
set
r.REV = d.REV,
r.NAME = d.NAME
Please see it working here.
As Hogan suggested, we could add something like where d.rev>r.rev since it should help giving better performances.
An alternative query, if you defined ID as a primary key, is:
insert into rootTable (ID, REV, NAME)
select * from deltaTable
on duplicate key update
REV=values(REV), NAME=values(NAME);
(this will update existing records, and add new ones).
Please see it here.
I have a database which contains product ID's and their rating out of 5 customers have given them. Each row in the database represents 1 review. Its quite simple and has the product ID and a 1 in the column where the review was 1, 2, 3, 4, or 5 star. It is laid out like this:
Product ID | 1 | 2 | 3 | 4 | 5 |
1294518 | 1 | 0 | 0 | 0 | 0 |
9226582 | 0 | 0 | 1 | 0 | 0 |
3946583 | 0 | 0 | 0 | 1 | 0 |
7392588 | 1 | 0 | 0 | 0 | 0 |
1196585 | 0 | 0 | 0 | 0 | 1 |
1196585 | 0 | 0 | 0 | 0 | 1 |
I want to merge the rows where I have duplicate product ID's. As per the example above there are two rows for product ID 1196585. In this case I would like to combine this into one row with a 2 under the 5 column to show this product has received two 5 star reviews.
To clarify I would like to modify the table in place so duplicate rows are combined, so that afterwards there are no duplicate product ID's and under each of the columns 1, 2, 3, 4 and 5 I am left with the number of times each of these product ID's has received a 1, 2, 3, 4 and 5 star review for example.
Please could you help me understand how this could be achieved with SQL?
This is a simple aggregation query:
select ProductId, sum(Rate_1) as Rate_1, sum(Rate_2) as Rate_3, sum(Rate_3) as Rate_3,
sum(Rate_4) as Rate_4, sum(Rate_5) as Rate_5
from t
group by ProductId
I changed the ostensible names of your columns to names using standard characters. 1 seems like a bad name for a column, for instance.
To modify the data in your table, you can use the following statement:
UPDATE product p
INNER JOIN (
SELECT "Product ID" as id,
SUM(product."1") AS s1,
SUM(product."2") AS s2,
SUM(product."3") AS s3,
SUM(product."4") AS s4,
SUM(product."5") AS s5
FROM product
GROUP BY id
HAVING count(*) > 1) sums
ON p.id = sums.id
SET p."1" = sums.s1, p."2" = sums.s2, p."3" = sums.s3, p."4" = sums.s4, p."5" = sums.s5
This will modify all your duplicated rows to be the same, with each column having the sum of the original rating counts. So all you have left to do is erase a bunch of duplicates, except for one. That has been asked a few times on StackOverflow, for example:
Remove duplicate rows in MySQL
How can I delete one of two perfectly identical rows?
My personal favorite is:
ALTER IGNORE TABLE product ADD UNIQUE INDEX ("Product ID")
I found a really easy way to do it was to export all the data into csv and open in excel and use the consolidate data function in excel then re-import back into MySQL. Not using SQL to make the amends but it was quicker and easier in the end.
May I suggest creating a view instead of combining the rows? That way you have your original data, in case you need it.
I'm taking over a database that needs to be presented in aCSV-friendly format for certain reasons.
Currently three tables exists. One with basic descriptions of an object, e.g.:
id | date | name
1 | 2008-10-10 | Maestro
2 | 2008-10-12 | Domo
Then I have another table containing event types and descriptions:
ev_id | desc | desc2
1 | Event1 | "Something less good happened"
2 | Event2 | "Something good happened"
Finally a third table making a connection between the two:
id | ev_id
1 | 2
2 | 1
What I need is to combine the three, such that each row in the event table produces a column in the final view together with the original object descriptions. If an event has occurred, a 1 should be inserted in the corresponding cell, otherwise 0 or NULL. E.g.:
id | date | name | Event1 | Event2
1 | 2008-10-10 | Maestro | 0 | 1
2 | 2008-10-12 | Domo | 1 | 0
Is this possible using SQL (MySQL)?
SELECT A.*,
(CASE WHEN B.ev_id = 1 THEN 1 ELSE 0 END) EVENT_1,
(CASE WHEN B.ev_id = 2 THEN 1 ELSE 0 END) EVENT_2,
.........
.........
(CASE WHEN B.ev_id = N THEN 1 ELSE 0 END) EVENT_N,
FROM table1 A JOIN table2 B
ON A.id = B.id
The only way to do this in mysql is to construct the query dynamicially by looping through the number of events in the events master table and then adding the same number of columns to the above query using dynamic sql and then execute.
SET #S = ' <construct the query> like the sample above ';
PREPARE n_StrSQL FROM #S;
EXECUTE n_StrSQL;
DEALLOCATE PREPARE n_StrSQL;
hope this helps
Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...