Simple While loop database search table - loops

first of all: Thanks for all the great help I already received through finding answers to questions others posted.
I have a small and easy question for you:
I'm trying to randomly generate a number, but if it exists in the database table, it should keep generating a new numbers until it finds a unique number.
Help would be much appreciated!
$klantnr = rand(1,9);
$kn = mysql_num_rows(mysql_query('select username from users where id="'.$klantnr.'"'));
while($kn!=0){
$klantnr = rand(1,9);
}
echo $klantnr;

Create table with:
id integer primary key auto_increment
insert into users (id, username) values (NULL, 'name')
insert into users (username) values ('name')
MySQL will generate unique id for you
=== update
create table random_id (
id integer,
used tinyint,
primary key(id),
key idx_used(used)
);
for (0..9999) {
rand_id = get_random_id();
insert into random_id (id, used) values (rand_id, 0);
}
When need a random id, just fetch one from random_id table:
rand_id = select id from random_id where used = 0;
update random_id set used = 1 where id = :rand_id
use rand_id
Really it's pre generated random id, if you guarantee the users table's id only from random table, you doesn't need dealing with conflict ids :)

Related

Update data when having UNIQUE Constraint

I am having a simple scores table for HTML5 game with columns: name, email and score. Email value should be a unique value, but when the same users play the game again to better their scores, the score should be updated for that user. Now it returns an error because of the unique value. How should I create a table that will update the data?
The table I have created so far:
CREATE TABLE `scores` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR( 20 ) NOT NULL,
`email` VARCHAR( 320 ) NOT NULL UNIQUE,
`score` INT NOT NULL,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB;
You could use an insert statement with an on duplicate key clause:
INSERT INTO scores (name, email, score)
VALUES ('some_name', 'some_email', 123) -- Values from your application
ON DUPLICATE KEY UPDATE
score = CASE VALUES(score) > score THEN VALUES(score) ELSE score END
It is not about your create table query, it is about your insert query.
Use a try catch method to update the unique value
try
{
// inserting the line
}
catch (exception)
{
// Drop the row with that unique value
// inserting the same line which you have added in "try" section
}

Validate number of rows depending on master row field value

I need to add a constraint to validate that number of rows referencing master table is lower than value in master row, e.g we have a table
master(master_id int pk, max_val int) and slave(slave_id int pk, master_id fk ref master(master_id)) (so slave is de facto a colection of something), and I want that count(master_id) in slave is <= than max_val for this master_id. I have a constraint
constraint NO_MORE_PASS check ((select count(head_id) from parts p where
p.head_id = head_id) <= (select max_val from head where id = head_id));
(not sure if it is correct, however SQL Server tells that subqueries are not allowed (sql server 2017) so...).
I have also read Check Constraint - Subqueries are not allowed in this context, so the question: is there any other alternative (I would like to avoid using trigger)?.
I'am using this in spring app with spring data jpa (and hibernate) - may be useful, but would like to make it on db side rather than in the app.
Nethertheless entity it is like:
#Entity
#Table(name = "route_parts")
data class RoutePart(
#Id
#Column(name = "route_part_id")
#GeneratedValue(strategy = GenerationType.AUTO)
var id: Long? = null,
//...
#Column(nullable = false)
var slots: Int? = null,
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "route_part_passengers",
joinColumns = [(JoinColumn(name = "route_part_id"))],
inverseJoinColumns = [(JoinColumn(name = "user_id"))]
)
var passengers: Set<ApplicationUser> = setOf()
)
and in that case ApplicationUser is a slave (or better - another table will be created, and actually this will be that slave table) limited by slots value.
So the question is...
How can I achieve limiting number of ApplicationUser attached to each RoutePart
If you want your check constraints to be based on queries, you must use a user defined function for the check constraint to work with.
Here is a quick example:
Tables:
CREATE TABLE dbo.Parent
(
Id int,
MaxNumberOfChildren int NOT NULL
);
CREATE TABLE dbo.Child
(
Id int,
ParentId int
);
User defined function (All it does is return the difference between the MaxNumberOfChildren and the number of records in the Child table with the same ParentId):
CREATE FUNCTION dbo.RestrictNumbrOfChildren
(
#ParentId int
)
RETURNS int
AS
BEGIN
RETURN
(
SELECT MaxNumberOfChildren
FROM dbo.Parent
WHERE Id = #ParentId
)
-
(
SELECT COUNT(Id)
FROM dbo.Child
WHERE ParentId = #ParentId
)
END;
Add the check constraint to the Child table:
ALTER TABLE dbo.Child
ADD CONSTRAINT chk_childCount CHECK (dbo.RestrictNumbrOfChildren(ParentId) >= 0);
And that's basically all you need, unless MaxNumberOfChildren is nullable.
In that case, you should add ISNULL() to the first query, with either 0 if null means no children are allowed, or the maximum value of int (2,147,483,647) if null means no restriction on the number of children - so it becomes SELECT ISNULL(MaxNumberOfChildren, 0)... or SELECT ISNULL(MaxNumberOfChildren, 2147483647)....
To test the script, let's insert some data to the Parent table:
INSERT INTO Parent (Id, MaxNumberOfChildren) VALUES
(1, 3), (2, 2), (3, 1);
And insert some valid data to the Child table:
INSERT INTO Child (Id, ParentId) VALUES
(1, 1), (2, 2);
So far, we have not exceeded the maximum number of records allowed. Now let's try to do that by insert some more data to the Child table:
INSERT INTO Child (Id, ParentId) VALUES
(3, 1), (4, 1), (5, 1);
Now, this insert statement will fail with the error message:
The INSERT statement conflicted with the CHECK constraint "chk_childCount". The conflict occurred in database "<your database name here>", table "dbo.Child", column 'ParentId'.
You can see a live demo on rextester.

Ensure foreign key of a foreign key matches a base foreign key

Basically let's say I have a "Business" that owns postal codes that it services. Let's also suppose I have another relational table that sets up fees.
CREATE TABLE [dbo].[BusinessPostalCodes]
(
[BusinessPostalCodeId] INT IDENTITY (1, 1) NOT NULL,
[BusinessId] INT NOT NULL,
[PostalCode] VARCHAR (10) NOT NULL
)
CREATE TABLE [dbo].[BusinessPostalCodeFees]
(
[BusinessId] INT NOT NULL,
[BusinessProfileFeeTypeId] INT NOT NULL,
[BusinessPostalCodeId] INT NOT NULL,
[Fee] SMALLMONEY NULL
)
I want to know if it's possible to set up a foreign key (or something) on BusinessPostalCodeFees that ensures that the related BusinessId of BusinessPostalCodes is the same as the BusinessId of BusinessPostalCodeFees.
I realize that I can remove BusinessId entirely, but I would much rather keep this column and have a way of guaranteeing they will be the same. Is there anything I can do?
It sounds like (and correct me if I'm wrong) that you're trying to make sure that any entry into BusinessPostalCodeFees' BusinessId and BusinessPostalCodeId columns match an entry in the BusinessPostalCodes table. If that's the case, then yes, you can definitely have a foreign key that references a compound primary key.
However, if you need to keep the BusinessId, I'd recommend normalizing your tables a step further than you have. You'll end up with duplicate data as-is.
On a side note, I would recommend you don't use the money data types in SQL: See here.
In the end, Jeffrey's solution didn't quite work for my particular situation. Both columns in the relation have to be unique (like a composite key). Turns out the answer here (for me) is a Checked Constraint.
Create a function that you want to have the constraint pass or fail:
CREATE FUNCTION [dbo].[MatchingBusinessIdPostalCodeAndProfileFeeType]
(
#BusinessId int,
#BusinessPostalCodeId int,
#BusinessProfileFeeTypeId int
)
RETURNS BIT
AS
BEGIN
-- This works because BusinessPostalCodeId is a unique Id.
-- If businessId doesn't match, its filtered out.
DECLARE #pcCount AS INT
SET #pcCount = (SELECT COUNT(*)
FROM BusinessPostalCodes
WHERE BusinessPostalCodeId = #BusinessPostalCodeId AND
BusinessId = #BusinessId)
-- This works because BusinessProfileFeeTypeId is a unique Id.
-- If businessId doesn't match, its filtered out.
DECLARE #ftCount AS INT
SET #ftCount = (SELECT COUNT(*)
FROM BusinessProfileFeeTypes
WHERE BusinessProfileFeeTypeId = #BusinessProfileFeeTypeId AND
BusinessId = #BusinessId)
-- Both should have only one record
BEGIN IF (#pcCount = 1 AND #ftCount = 1)
RETURN 1
END
RETURN 0
END
Then just add it to your table:
CONSTRAINT [CK_BusinessPostalCodeFees_MatchingBusinessIdPostalCodeAndProfileFeeType]
CHECK (dbo.MatchingBusinessIdPostalCodeAndProfileFeeType(
BusinessId,
BusinessPostalCodeId,
BusinessProfileFeeTypeId) = 1)

String with commas and references table?

I have a legacy VB application that we are maintaining. A design decision we took was to store certain data points as concatenated strings. This change is set in stone as the majority of code is complete.
I'm running a loop through an array of values. What I'm doing is, looking up a LABEL for each value in a reference table. I need to be able to display the values in one label. I'm having a difficult time concetenating the values into a string and then displaying it in a label. Here is my code...
If strField = "Expenditures" Then
If InStr(1, strOldValue, ",") > 0 Then
strArray = Split((strOldValue), ",")
For x = 0 To UBound(strArray)
For Each item In strArray
strMessage = DLookUp(1, "Label", "tblText_References", "ID = '" & item & "'
**''''******here I'm trying to save teh value in strMessage, however, at next item, I need it to be added to strMessage in some fashion, with a (,), I'm not sure how to do it. There are anywhere from 2 to 4 ITEMS i might have.**
Next item
Next
End if
End if
You should definitely reconsider how you are storing the meal data. Never store multiple values in a single column concatenated by commas. Instead, you want to create a table to contain the selected items, which can then be JOINed to other tables, utilizing a one-to-many relationship.
The following code shows an example of how you might accomplish this.
Create a table to contain Users who will have Meals associated with them:
CREATE TABLE dbo.Users
(
UserID INT NOT NULL
CONSTRAINT PK_Users
PRIMARY KEY CLUSTERED
, UserName VARCHAR(255) NOT NULL
);
Create a table to describe the Meals:
CREATE TABLE dbo.Meals
(
MealID INT NOT NULL
CONSTRAINT PK_Meals
PRIMARY KEY CLUSTERED
, MealName VARCHAR(255) NOT NULL
);
Create a junction table that joins the Users to their Meals:
CREATE TABLE dbo.UserMeals
(
UserID INT NOT NULL
, MealID INT NOT NULL
, CONSTRAINT PK_UserMeals
PRIMARY KEY CLUSTERED (UserID, MealID)
);
Insert a sample user:
INSERT INTO dbo.Users (UserID, UserName)
VALUES (1, 'Test User');
Insert the 4 meals:
INSERT INTO dbo.Meals (MealID, MealName)
VALUES (80, 'Breakfast')
, (81, 'Lunch')
, (82, 'Dinner')
, (83, 'Snack');
Insert some sample rows into the UserMeals table that associate meals with users:
INSERT INTO dbo.UserMeals (UserID, MealID)
VALUES (1, 80)
, (1, 81);
Show the users with their associated meals:
SELECT u.UserName
, m.MealName
FROM dbo.UserMeals um
INNER JOIN dbo.Users u ON um.UserID = u.UserID
INNER JOIN dbo.Meals m ON um.MealID = m.MealID;
The results:
this is all the code that's needed. I created a new variable called strNEWmessage as string. I already had a variable called strMessage as string The answer is: strNewMessage = strNewMessage & "," strMessage

T-SQL - In Single Stored procedure want to pass value(result) of one query to another query as input

I have a Stored procedure, in which I have to insert 3 strings into 3 different Tables at a time, each string into each of the 3 tables.
In each table, a unique primary key (rowid) would be generated on insertion of the value.
Now, the Primary Key of first two tables is the Foreign key of the Third Table which as you all know, should not be null.
Here in my SP, insertion of value and generation of RowID (PrimaryKey) is done successfully.
Now I have to pass the two primary keys(Rowids) as values/Parameters(foreignkeys) into the third table, which is returning null.
Here is my SP:-
(1st Table)
INSERT INTO [kk_admin].[FA_Master](FA_Name,FA_CSession,FA_MSession) Values
(#FA_Name,#Session_Id,#Session_Id)
SELECT #**FA_ID=FA_ID** FROM [kk_admin].[FA_Master] where FA_Name=#FA_Name
(2nd Table)
INSERT INTO [kk_admin].[Dept_Master](Dept_Name,Dept_CSession,Dept_MSession) Values
(#Dept_Name,#Session_Id,#Session_Id)
SELECT #**Dept_id=Dept_id** from [kk_admin].[Dept_Master] where Dept_Name=#Dept_Name
(3rd Table)
INSERT INTO [kk_admin].[Category_Master] (**FA_Id**,**Dept_Id**,Category_Name,Category_CSession,Category_MSession) Values (#**FA_ID**,#**Dept_Id**,#Category_Name,#Session_Id,#Session_Id)
Hope everyone understood what I have explained.
Plz Help me,
Iam running out of time.
Plz help me.
Thank You in Advance,
Brightsy
You can use an OUTPUT clause (assuming you're using SQL Server 2005) to capture the primary key for the two rows you're inserting with the first two queries. You can capture the values into a temporary table. [I previously wrote that you could use a regular variable, but that's not supported.] Example code:
CREATE TABLE #FA_Master_ID ( ID int );
CREATE TABLE #Dept_Master_ID ( ID int );
INSERT kk_admin.FA_Master ( FA_Name, FA_CSession, FA_MSession )
OUTPUT INSERTED.ID INTO #FA_Master_ID
VALUES ( #FA_Name, #Session_Id, #Session_Id );
INSERT kk_admin.Dept_Master ( Dept_Name, Dept_CSession, Dept_MSession )
OUTPUT INSERTED.ID INTO #Dept_Master_ID
VALUES ( #Dept_Name, #Session_Id, #Session_Id );
INSERT kk_admin.Category_Master ( **FA_Id**, **Dept_Id**, Category_Name, Category_CSession, Category_MSession )
SELECT **FA_Id** = ( SELECT TOP 1 ID FROM #FA_Master_ID ),
**Dept_Id** = ( SELECT TOP 1 ID FROM #Dept_Master_ID ),
Category_Name = #Category_Name,
Category_CSession = #Session_Id,
Category_MSession = #Session_Id;

Resources