MySQL Query - Check if data row contains a user_id - mysql

I have a sessions table and what I am trying to do is run a query to check if a certain account is logged in.
My query looks like this:
SELECT id FROM sessions WHERE data LIKE '%4%'
But with a query like that, if the user_id of "14" is logged in, that query will return True. How do I check to see if a certain number exists and matches exactly?

Include the delimiters in your search:
WHERE data LIKE '%:4;%'

why don't you add another field for user_id to the session table?
EXAMPLE:
I have a site where a user can only be logged in from one location at a time. If they try and log in from another location (IE start a new session) then i kill all of their previous logins.
So as part of my login script:
// log this user out of any other active sessions
$sql = sprintf("DELETE
FROM sessions
WHERE id_user=%s",
mysql_real_escape_string($_SESSION['id_user'])
);
// Associate this session with this user
$sql = sprintf("UPDATE sessions
SET id_user=%s
WHERE id=%s",
mysql_real_escape_string($_SESSION['id_user']),
session_id()
);
and so i can have id_user as an additional field in my session FKed to my user table... its a little more normalized and lets you do quick "Who is currently using this site" queries without too much parsing and fuss.

Related

Do i have to make 2 queries to authorize a User in an API?

Lets say i have 2 tables:
User (id, name)
Notes (id, userID, text)
Now i make a request to my API and supply the User ID. I want to change the text of a certain Note, but only if the User is also the author of that note.
Lets say my User ID is stored in a variable { uID } at the backend.
Do i have to query
"SELECT userID FROM Notes..."
first and compare the result to my uID variable and afterwards execute
"UPDATE Notes..." ?
It works, but it feels kind of wonky.
Is there a more elegant solution?
You can easily use a where clause:
UPDATE notes SET ... WHERE userID='uID'

Joomla 3x - Profile Fields

I have added a checkbox to the user profile and need to know how to get a list of all the user email addresses where they have checked the checkbox. I would like to just run a SQL query, but can't see where the value is stored.
All the profile data is stored in #__user_profiles table. To retrieve the data from the profile table you can perform this query
// Get a db connection.
$db = JFactory::getDbo();
// Create a new query object.
$query = $db->getQuery(true);
// Select all records from the user profile table where key begins with "checkbox.".
// Order it by the ordering field.
$query->select($db->quoteName(array('user_id', 'profile_key', 'profile_value')));
$query->from($db->quoteName('#__user_profiles'));
$query->where($db->quoteName('profile_key') . ' LIKE '. $db->quote('\'checkbox.%\''));
// Reset the query using our newly populated query object.
$db->setQuery($query);
// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$results = $db->loadObjectList();
You will get object list of all those users who clicked on your checkbox. Remember to use the profile_key name in place of checkbox
Ok - I have now managed to answer my own question (I took an export of the database as a SQL file, ticked the checkbox as a test user, made another export and then compared the files to see what had changed).
The values are stored in the jos_fields_values table. The query below assumes that there is only one checkbox - if you have more than one you will need to query the field_id as well, Replace xxx with the prefix of your Joomla installation.
SELECT email FROM xxx_users INNER JOIN xxx_fields_values ON xxx_users.ID=xxx_fields_values.item_id

How to select a row just once without checking any fields in SQL

I have a table named tblMessages that has a field named Type .type value can be 1 for user messages and can be 2 for general messages.
in selection of user message i write this sql function:
SELECT * FROM tblMessage WHERE USERID=$Userid and Type=1 and ISseen=0;
then in another SQL code i updated that row and set ISseen=1 for specific user
UPDATE tblMessage SET ISseen=1 Where USERID=$userid;
but in selection of General messages i have a little problem.i want to select general message for all user and show it once!as i said before i can update tblmessage and set ISseen=1 then if ISseen be a value of 1 user message is not selected for another time.but for selection of general message i cant do it with WHERE USERID=$userid.
i dont want to insert general message for every user in table also.then
How can i select general messages ONCE for a user by my table structure?
*****////******
Edit number 1
my tblmessage has 20000 records and just has 10 general messages.in my website when user loged in to his/her acount and go to his/her messages can see Personal Messages and General Messages.when user reach that page i Updated the tblmessage table and set ISseen==1
then when that user loged out and then came back to website and to his/her userpage that personal message didnt show again!cause the field ISseen=1.But in another way the general messages is showed again and again.cause what?cause i dont have any ISseen field for general message.
my question is what can i do then with this explanation of my table.how can i do the same thing with general messages.
Create another table messageTable that will look like this .
ID -- Message
1 -- User message
2 -- General message
now you can apply join to get message on the behalf of type .
your query will be look like this.
SELECT messageTable.*,tblMessage.* FROM tblMessage,messageTable WHERE tblMessage.USERID=$Userid and tblMessage.Type=1 and tblMessage.ISseen=0 and tblMessage.Type=messageTable.ID;

Erratic Problems Adding User ID to MySQL Table of User Lists

I have a site where users can log-in and add items to a list.
The user logs in and the session stores their e-mail, which I use to identify them in a user table.
Then, they can input a list item and add to a list table that contains their ID and their list items.
Sometimes the ID is added and sometimes it comes up null (however, the list item text is always added). This seems erratic because most of the time the ID is included.
Any ideas? The table type is MyISAM. I'm new to programming, btw.
Here's an example of my code:
<?php
session_start();
$item = $_REQUEST['item'];
$email = $_SESSION['email'];
if ($item)
{
mysql_connect("localhost","root","") or die("We couldn't connect!");
mysql_select_db("table");
$query = mysql_query("SELECT ID FROM users WHERE email='".$_SESSION['email']."'");
$result = mysql_result($query,0);
$user_id = $result;
mysql_query("INSERT INTO items (user_ID,item_name) VALUES('$user_id','$item')");
So every time I test it by logging into my site myself, no problems. But increasingly, I have users who try to add items and it creates a record where item_name shows up correctly but user_ID is set to 0 (default).
First off, read what I said about SQL injection attacks in the comments to your question.
It would be a good idea to store the user_id in the $_SESSION so you wouldn't have to query for it every time based on the email... but if you insist on just having the email in the $_SESSION, then you actually only need one query. Adjusted code:
<?php
session_start();
$item = mysql_real_escape_string($_REQUEST['item']);
if (!empty($item) && isset($_SESSION['email']))
{
mysql_connect("localhost","root","") or die("We couldn't connect!");
mysql_select_db("table");
mysql_query("INSERT INTO items (user_ID, item_name) VALUES ((SELECT ID FROM users WHERE email='{$_SESSION['email']}'), '$item')");
}
Like Jeff Watkins said, the session could be timed out, so it would be a good idea to first check if it's set using isset().
Otherwise if you stored the userid in the session, you could just reference it directly as $_SESSION['user_id'] instead of doing a subquery in the insert.

Is this a case for denormalisation?

I have a site with about 30,000 members to which I'm adding a functionality that involves sending a random message from a pool of 40 possible messages. Members can never receive the same message twice.
One table contains the 40 messages and another table maps the many-to-many relationship between messages and members.
A cron script runs daily, selects a member from the 30,000, selects a message from the 40 and then checks to see if this message has been sent to this user before. If not, it sends the message. If yes, it runs the query again until it finds a message that has not yet been received by this member.
What I'm worried about now is that this m-m table will become very big: at 30,000 members and 40 messages we already have 1.2 million rows through which we have to search to find a message that has not yet been sent.
Is this a case for denormalisation? In the members table I could add 40 columns (message_1, message_2 ... message_40) in which a 1 flag is added each time a message is sent. If I'm not mistaken, this would make the queries in the cron script run much faster
?
I know that doesn't answer your original question, but wouldn't it be way faster if you selected all the messages that weren't yet sent to a user and then select one of those randomly?
See this pseudo-mysql here:
SELECT
CONCAT_WS(',', messages.ids) unsent_messages,
user.id user
FROM
messages,
user
WHERE
messages.id NOT IN (
SELECT
id
FROM
sent_messages
WHERE
user.id = sent_messages.user
)
GROUP BY ids
You could also append the id of the sent messages to a varchar-field in the members-table.
Despite of good manners, this would make it easily possible to use one statement to get a message that has not been sent yet for a specific member.
Just like this (if you surround the ids with '-')
SELECT message.id
FROM member, message
WHERE member.id = 2321
AND member.sentmessages NOT LIKE '%-' && id && '-%'
1.2 M rows # 8 bytes (+ overhead) per row is not a lot. It's so small I wouldn't even bet it needs indexing (but of course you should do it).
Normalization reduces redundancy and it is what you'll do if you have large amount of data which seems to be your case. You need not denormalize. Let there be an M-to-M table between members and messages.
You can archive the old data as your M-to-M data increases. I don't even see any conflicts because your cron job runs daily for this task and accounts only for the data for the current day. So you can archive M-to-M table data every week.
I believe there will be maintenance issue if you denormalize by adding additional coloumns to members table. I don't recommend the same. Archiving of old data can save you from trouble.
You could store only available (unsent) messages. This implies extra maintenance when you add or remove members or message types (nothing that can't be automated with foreign keys and triggers) but simplifies delivery: pick a random line from each user, send the message and remove the line. Also, your database will get smaller as messages get sent ;-)
You can achieve the effect of sending random messages by preallocating the random string in your m-m table and a pointer to the offset of the last message sent.
In more detail, create a table MemberMessages with columns
memberId,
messageIdList char(80) or varchar ,
lastMessage int,
primary key is memberId.
Pseudo-code for the cron job then looks like this...
ONE. Select next message for a member. If no row exists in MemberMessages for this member, go to step TWO. The sql to select next message looks like
select substr(messageIdList, 2*lastMessage + 1, 2) as nextMessageId
from MemberMessages
where member_id = ?
send the message identified by nextMessageId
then update lastMessage incrementing by 1, unless you have reached 39 in which case reset it to zero.
update MemberMessages
set lastMessage = MOD(lastMessage + 1, 40)
where member_id = ?
TWO. Create a random list of messageIds as a String of couplets like 2117390740... This is your random list of message IDs as an 80 char String. Insert a row to MemberMessages for your member_id setting message_id_list to your 80 char String and set last_message to 1.
Send the message identified by the first couplet from the list to the member.
You can create a kind of queue / heap.
ReceivedMessages
UserId
MessageId
then:
Pick up a member and select message to send:
SELECT * FROM Messages WHERE MessageId NOT IN (SELECT MessageId FROM ReceivedMessages WHERE UserId = #UserId) LIMIT 1
then insert MessageId and UserId to ReceivedMessages
and do send logic here
I hope that helps.
There are potential easier ways to do this, depending on how random you want "random" to be.
Consider that at the beginning of the day you shuffle an array A, [0..39] which describes the order of the messages to be sent to users today.
Also, consider that you have at most 40 Cron jobs, which are used to send messages to the users. Given the Nth cron job, and ID the selected user ID, numeric, you can choose M, the index of the message to send:
M = (A[N] + ID) % 40.
This way, a given ID would not receive the same message twice in the same day (because A[N] would be different), and two randomly selected users have a 1/40 chance of receiving the same message. If you want more "randomness" you can potentially use multiple arrays.