简体   繁体   中英

How do I end a SQL case statement if one of the case statements is met?

I'm currently building an app that has a database that holds the users inventory that consists of forty slots. In this database one row is equal to one user. What I want this query to do is search through each slot and when it finds a slot that has a zero in it, the query should then update it to a different predetermined number and then stop. However I've ran into a problem with the solution that I've found, instead of the query stopping after it updates a specific node, it continues to update every single node that has a zero in it. How can I end this query after it updates one node?

CODE:

SET SQL_SAFE_UPDATES = 0;
SELECT *
FROM userinfo;

UPDATE userinfo SET
InvSlot1 = CASE WHEN InvSlot1 = 0 THEN 4 ELSE InvSlot1 END,
InvSlot2 = CASE WHEN InvSlot2 = 0 THEN 4 ELSE InvSlot2 END,
InvSlot3 = CASE WHEN InvSlot3 = 0 THEN 4 ELSE InvSlot3 END,
InvSlot4 = CASE WHEN InvSlot4 = 0 THEN 4 ELSE InvSlot4 END,
InvSlot5 = CASE WHEN InvSlot5 = 0 THEN 4 ELSE InvSlot5 END,
InvSlot6 = CASE WHEN InvSlot6 = 0 THEN 4 ELSE InvSlot6 END,
InvSlot7 = CASE WHEN InvSlot7 = 0 THEN 4 ELSE InvSLot7 END,
InvSlot8 = CASE WHEN InvSlot8 = 0 THEN 4 ELSE InvSlot8 END,
InvSlot9 = CASE WHEN InvSlot9 = 0 THEN 4 ELSE InvSlot9 END,
InvSlot10 = CASE WHEN InvSlot10 = 0 THEN 4 ELSE InvSlot10 END,
InvSlot11 = CASE WHEN InvSlot11 = 0 THEN 4 ELSE InvSlot11 END,
InvSlot12 = CASE WHEN InvSlot12 = 0 THEN 4 ELSE InvSlot12 END,
InvSlot13 = CASE WHEN InvSlot13 = 0 THEN 4 ELSE InvSlot13 END,
InvSlot14 = CASE WHEN InvSlot14 = 0 THEN 4 ELSE InvSlot14 END,
InvSlot15 = CASE WHEN InvSlot15 = 0 THEN 4 ELSE InvSlot15 END,
InvSlot16 = CASE WHEN InvSlot16 = 0 THEN 4 ELSE InvSlot16 END,
InvSlot17 = CASE WHEN InvSlot17 = 0 THEN 4 ELSE InvSlot17 END,
InvSlot18 = CASE WHEN InvSlot18 = 0 THEN 4 ELSE InvSlot18 END,
InvSlot19 = CASE WHEN InvSlot19 = 0 THEN 4 ELSE InvSlot19 END,
InvSlot20 = CASE WHEN InvSlot20 = 0 THEN 4 ELSE InvSlot20 END,
InvSlot21 = CASE WHEN InvSlot21 = 0 THEN 4 ELSE InvSlot21 END,
InvSlot22 = CASE WHEN InvSlot22 = 0 THEN 4 ELSE InvSlot22 END,
InvSlot23 = CASE WHEN InvSlot23 = 0 THEN 4 ELSE InvSlot23 END,
InvSlot24 = CASE WHEN InvSlot24 = 0 THEN 4 ELSE InvSlot24 END,
InvSlot25 = CASE WHEN InvSlot25 = 0 THEN 4 ELSE InvSlot25 END,
InvSlot26 = CASE WHEN InvSlot26 = 0 THEN 4 ELSE InvSlot26 END,
InvSlot27 = CASE WHEN InvSlot27 = 0 THEN 4 ELSE InvSlot27 END,
InvSlot28 = CASE WHEN InvSlot28 = 0 THEN 4 ELSE InvSlot28 END,
InvSlot29 = CASE WHEN InvSlot29 = 0 THEN 4 ELSE InvSlot29 END,
InvSlot30 = CASE WHEN InvSlot30 = 0 THEN 4 ELSE InvSlot30 END,
InvSlot31 = CASE WHEN InvSlot31 = 0 THEN 4 ELSE InvSlot31 END,
InvSlot32 = CASE WHEN InvSlot32 = 0 THEN 4 ELSE InvSlot32 END,
InvSlot33 = CASE WHEN InvSlot33 = 0 THEN 4 ELSE InvSlot33 END,
InvSlot34 = CASE WHEN InvSlot34 = 0 THEN 4 ELSE InvSlot34 END,
InvSlot35 = CASE WHEN InvSlot35 = 0 THEN 4 ELSE InvSlot35 END,
InvSlot36 = CASE WHEN InvSlot36 = 0 THEN 4 ELSE InvSlot36 END,
InvSlot37 = CASE WHEN InvSlot37 = 0 THEN 4 ELSE InvSlot37 END,
InvSlot38 = CASE WHEN InvSlot38 = 0 THEN 4 ELSE InvSlot38 END,
InvSlot39 = CASE WHEN InvSlot39 = 0 THEN 4 ELSE InvSlot39 END,
InvSlot40 = CASE WHEN InvSlot40 = 0 THEN 4 ELSE InvSlot40 END
WHERE Username = 'test' 

Here's an ugly hack solution to do what you want.

First, define a User-defined session variable with the value you want to put into your table.

SET @x := 4;

Then do your big-ass UPDATE statement like before, but set the slot to your @x variable, with something extra: as part of the expression, you also add the result of a new assignment to the variable to zero. Adding zero doesn't affect the result, but it has the side-effect that the value of @x is changed to zero, and this is used in subsequent slot assignments until the end of the query.

Only the first slot that was previously zero triggers the expression that changes @x , but any subsequent slot that is zero is just set to zero again, which has no effect.

UPDATE userinfo SET
InvSlot1 = CASE WHEN InvSlot1 = 0 THEN @x+(@x:=0) ELSE InvSlot1 END,
InvSlot2 = CASE WHEN InvSlot2 = 0 THEN @x+(@x:=0) ELSE InvSlot2 END,
InvSlot3 = CASE WHEN InvSlot3 = 0 THEN @x+(@x:=0) ELSE InvSlot3 END,
InvSlot4 = CASE WHEN InvSlot4 = 0 THEN @x+(@x:=0) ELSE InvSlot4 END,
...

That's a hack that may work with your current database design.

However, I agree with the other commenters on this question and your previous question —you should not organize your database this way.

Instead, create another table that has up to 40 rows per user. You don't need a table per user, if you include a userid column in the table, so you can repeat the 40 rows for each user, and designate which slots belong to which user.

To restrict the slots to no more than 40, create a lookup table to enumerate the 40 rows and use a foreign key constraint. (You can expand to 43 slots in the future simply by adding three more rows to this table.)

CREATE TABLE slots ( slot TINYINT PRIMARY KEY );
INSERT INTO slots (slot) VALUES (1), (2), (3), (4), ... 

CREATE TABLE userinfoInvslots (
  userid INT NOT NULL,
  slot TINYINT NOT NULL,
  slotvalue INT NOT NULL,
  PRIMARY KEY (userid, slot),
  FOREIGN KEY (slot) REFERENCES slots(slot)
);

Now instead of using zero to mean a slot is unoccupied, you would just not insert a row for that slot number. The absence of a row means the slot is unused. Clearing a slot would be done by deleting a row in this table.

Querying for the lowest unused slot is easy:

SELECT MIN(s.slot) AS minSlot
FROM slots AS s
LEFT OUTER JOIN userinfoInvslots AS u
  ON s.slot = u.slot and u.userid = 1234
WHERE u.slot IS NULL;

Re comments from @CRSoftware33

So if I have the users username as a primary key in my first table, would I use that in the second table as the primary key for that table?(I'm fairly new to SQL) and would I then only have two columns in my second table, one for the username and one for the int value that will be stored in the inventory slot?

I showed a column userid under the assumption that you have an integer primary key in the userinfo table, but if you have username as the primary key, then yeah use that.

I don't really know how I would make this work, because in my there are exactly forty slots, and in my GUI there are forty ImageViews which correspond to each slot in my inventory. How can I replicate this with two tables?

When you want to show the slots for a given user, query the userinfoInvslots table WHERE userid=? and get the 40 rows corresponding to the user you want. Then loop over this result set in your code. As you fetch rows, display them.

would there be a way to make a query that would generate the users inventory in my second table which consists of a username column, a slot column and an item id column? So in other words, it would be one query that would add forty rows and would add the users username for each column and would number their slot column from one to forty and would set each item id to zero for each row?

Yes, you could do it in SQL but honestly it's simpler to do it in a loop in your application code. Count from 1 to 40 with a loop variable and insert one row in each iteration of the loop. I don't mean to sound insulting, but this is really basic stuff that you learn in any class or any book.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM