Need a big help from you.
I need an advice from all you good people out there.
I have some contents that i need to display only to few countries.I am okay with getting the user's country with Geoip.i am storing my content in MySQL database with a country_code field.country code can be empty or any single code or group of comma separated values
What i want to do is,
checking country_code and if it is empty, display that content for all users.
if country_code is not empty and only a single value,display content only for the given country_code users.
if country_code is group of comma separated values,display contents for all the comma separated country users.
i have two options for do this
adding data columns for each country separately and display contents
as for example three columns for three countries US,UK,AU and if user's location is US,
$sql=mysql_fetch_array(mysql_query("SELECT * FROM content_table WHERE US=='$country_code'"));
adding country data for single column as country_code and store US,UK,AU and if user's location is US,
$sql=mysql_fetch_array(mysql_query("SELECT * FROM content_table WHERE country_code!=''"));
$pieces = explode(",", $sql['country_code']);
foreach($pieces as $val){
if($country_code=="US")
//display content
}
NOTE:amount of countries may differs according to my needs
what will be the best practice to overcome this,
using different columns to different country make fast search but adding more columns is not good i think
using single column and iterate comma separated values needs more computation
What should i do..??
please advice me on this.. OR do you have any idea better than this..? Thanks
I'd just say - create a countries table
countries
id, code, name
1, UK , United Kingdom
..... and rest of the countries
In your content table just add another column country_id or country_code
Content
id, title, body, country_code
1, some text, more text, 1
then in your sql
just select * from content where country_code = 'UK' or country_id = 1 // depending on which option you go for
OR
create a separate linking table for allowing content for multiple countries
content_country
content_id, country_id
1, 2
1, 1
1, 3
To fetch content your queries use left/right/inner join e.g.
SELECT *
FROM `content` c
LEFT JOIN content_country cc ON cc.content_id = c.id
AND cc.country_id
IN ( 2, 4 )
$sql=mysql_fetch_array(mysql_query("SELECT *
FROM content_table
WHERE country_code = ''
OR country_code REGEXP ',?". $user_country_code .",?'"));
If I understood you well, you want to show elements to the user only if the user country code is in the country_code field or if the country_code is not specified ?
This should do it, even if a database solution would be better.
Try It:
$sql=mysql_fetch_array(mysql_query("SELECT * FROM content_table WHERE country_code!=''"));
$pieces = explode(",", $sql['country_code']);
# No Need to run loop
#foreach($pieces as $val)
#{
# if($country_code=="US") //display content
#}
if(!empty($pieces)) //
{
if(in_array($user_country_code,$pieces ))
{
echo "display content";
}
}
else
{
echo "display content"; // for all country
}
Use in_array() except of loop. I guess you will use in on user login so you will have user_country_code.
Related
I have a table with users and one with labels
A label can have many users and a user can have many labels, so a Many to Many relationship
A joining table is needed, that's why I have label_user
Below you can see pictures of what they contain with example data:
Users:
https://i.stack.imgur.com/E5E6O.png
Labels:
https://i.stack.imgur.com/1NFjq.png
label_user:
https://i.stack.imgur.com/tW2Uo.png
Let's say I have 5000 users and I can sort them by gender. Let's say 2800 of them are males, how can I assign them all to a label?
Here's some things I tried:
public function add_users_to_label($label_id, $condition, $value)
{
$db = new Database();
$conn = $db->db_connect();
$label_id = escape_string($conn, $label_id);
$query = $conn->query("INSERT INTO `label_user`(`label_id`, `user_id`) SELECT :label_id, psid FROM `iris_messenger_users` WHERE $condition = $value");
$query->bind_param("iss", $label_id, $condition, $value);
if ($query->execute()) {
return true;
}
else {
return "Error inserting data: " . $conn->error . "\n";
}
}
On the user side I have a simple form with select that let's you select a label and then this code:
if(isset($_POST['label-select'])) {
if ($_GET['show_only_gender'] == 'male') {
$condition = 'gender';
$user->add_users_to_label($_POST['label-select'], $condition, $_GET['show_only_gender']);
}
}
Basically, I want to get all users that are male and assign them to a label and put that into label_user with respectively the label_id and the user_id(psid)
Even if this worked I'd still have to do it 2699 times more. What can I do here to optimize and make it to run with 1 query if possible?
I don't think using foreach and running it as much times as there are users is the best option, is it?
Is there any better approach I can take to make this possible?
Although what you are describing does not make sense to have a "label" associated with a person for this specific component, the gender is already on the user table you should be able to get all male based on
select * from user where gender = 'male'
no need to JOIN to a label table on this field. Similarly if you were trying to find people based on a name starting with something... you would not create a label for the name either. Query directly from the table that has that specific component association.
Now, to answer your question, how to insert into the label table for each instance in bulk, you could do something like... I am doing this based on some label ID = 123 as just an example in your labels table that represents gender.
I am doing a LEFT-JOIN in the select so we dont try to add for any user IDs that are already on file do not try to get re-added.
insert into label_user
( label_id,
user_id )
select
123 as label_id,
U.id as user_id
from
users U
left join label_user LU
on U.id = LU.user_id
AND LU.label_id = 123
where
U.gender = 'male'
AND LU.user_id IS NULL
You obviously need to adjust for php.
I have a query a Wordpress include which does the following:
$sql = "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'merchant_id' LIMIT 6";
$results = $wpdb->get_results($sql);
foreach ($results as $row)
{
echo $row->meta_value . ",";
//sprintf("SELECT * FROM retailers WHERE advertiserId = '%s'", $row->meta_value);
}
//clean all results
$wpdb->flush();
It parses all pages custom fields (merchant ID numbers), and returns any unique distinct values, separated by a comma. This bit works great.
ie: The above may return: 1301,345,723,134,1435
What I also have is a separate MySQL table of about 20 fields, three of which are the MerchantID, programmeName, and commissionMax. Each value from the CSV correlates with the MerchantID in the database.
Regardless of the amount of merchant ID's that appear in the CSV - I need to parse them all, but show the three highest commission rates (commissionMax), as well as the programmeName.
I managed to get connected to my external database and retrieve the appropriate values (using the commented code above) however this showed all of the retailers information.
Any advice?
Use the following query with limit:
SELECT * // select all fields
FROM table_name // from your table
WHERE MerchantID IN (your_ids_here) // IDs received from previous query or wherever
ORDER BY commissionMax DESC // descending sort by commissionMax field
LIMIT 3 // take first 3 results
I've concatenated 2 fields in a form's drop down list, with the 2 fields being First Name and Last Name; This allowed me to display a person's full name.
The issue is that in the database a person's full name is stored in 2 seperate fields; First Name and Last Name.
I need to match the person's full name (from the dropdown list) to the First Name and Last Name in the DB, however I am struggling to achieve this.
The php code for the concatenated form list is:
<td>
<select name='IndivSurname'>";
while($FullName_row = odbc_fetch_array($sql_run_FullName)){
$IndivFirstName=$FullName_row['FirstName'];
$IndivLastName=$FullName_row['LastName'];
echo"<option value='$IndivIndivId' . '$IndivTenantNdx'> $IndivFirstName $IndivLastName</option>";
}
</select>
</td>
While the SQL statement is:
SELECT EventId, EventTime, Individual, Tenant, TenantName, DeviceName, Comment,
InetDb.dbo.Individuals.FirstName, InetDb.dbo.Individuals.LastName
FROM taclogdata.dbo.Event
LEFT JOIN InetDb.dbo.Tenants
ON taclogdata.dbo.Event.Tenant = InetDb.dbo.Tenants.TenantId
LEFT JOIN InetDb.dbo.Individuals
ON taclogdata.dbo.Event.Individual = InetDb.dbo.Individuals.IndivId
AND taclogdata.dbo.Event.Tenant = InetDb.dbo.Individuals.TenantNdx
WHERE (taclogdata.dbo.Event.EventTime BETWEEN '00:00:00 05/26/2015'
AND '09:00:00 05/26/2015'
AND (taclogdata.dbo.Event.Comment ='Reader entry'
OR taclogdata.dbo.Event.Comment='Reader exit')
AND (InetDb.dbo.Individuals.FirstName = '$IndivFirstName'
AND InetDb.dbo.Individuals.LastName = '$IndivLastName')";
Many thanks in advance
The easiest way to do this, is by splitting the string on the space. However, that introduces a bug if the person has more than one first- or surname. This means that in the cases where we have 3 or more elements in the result of the split, we'll have to add the middle elements to both matches; Seeing as we don't know whether it's a surname or middle name.
That is why I recommend using a different character for the glue in the value attribute, one which is never used in a name. # is one such character.
This leaves you with the following code for the form-generation:
// CF: Added HTML-escaping to prevent XSS-attacks.
$IndivFirstName=htmlspecialchars ($FullName_row['FirstName']);
$IndivLastName=htmlspecialchars ($FullName_row['LastName']);
echo"<option value='{$IndivFirstName}#{$IndivLastName}'> $IndivFirstName $IndivLastName</option>";
In the SQL-statement you can do the following (using prepared statements):
$stmt = $db->prepare ("SELECT EventId, EventTime, Individual, Tenant, TenantName, DeviceName, Comment, InetDb.dbo.Individuals.FirstName, InetDb.dbo.Individuals.LastName
FROM taclogdata.dbo.Event
LEFT JOIN InetDb.dbo.Tenants
ON taclogdata.dbo.Event.Tenant = InetDb.dbo.Tenants.TenantId
LEFT JOIN InetDb.dbo.Individuals
ON taclogdata.dbo.Event.Individual = InetDb.dbo.Individuals.IndivId
AND taclogdata.dbo.Event.Tenant = InetDb.dbo.Individuals.TenantNdx
WHERE (taclogdata.dbo.Event.EventTime BETWEEN '00:00:00 05/26/2015' AND '09:00:00 05/26/2015'
AND (taclogdata.dbo.Event.Comment ='Reader entry' OR taclogdata.dbo.Event.Comment='Reader exit')
AND (InetDb.dbo.Individuals.FirstName = :firstname AND InetDb.dbo.Individuals.LastName = :lastname)");
$name = explode ("#", $_POST['IndivSurname']);
$stmt->exec (array (":firstname" => $name[0], ":lastname" => $name[1]));
Splitting on spaces is not going to be reliable given the number of De Aches and Mc Pains in this world.
The really sure way of doing this is to save the first name and last name in a hidden table within your form (in the same order as your pulldown).
A possible alternative is to concatenate using a not a space but one of the other white space characters like NO BREAK SPACE "\u00A0" which you can then reliably split later.
Ok I solved my problem by POSTing the user's PK rather than his First Name and Last Name individually, and search using those characteristics.
However I introduced the explode function as per the below to separate the concatenated values as per the below:
SQL query selects the IndivId, TenntNdx, individual's first name and last name, however only the first name and last name of the user are displayed in the form's drop down list. The matching IndivId and TenantNdx are posted using the code below:
$sql_FullName = "SELECT IndivId, TenantNdx, FirstName, LastName FROM InetDb.dbo.Individuals
ORDER BY FirstName ASC";
$sql_run_FullName = odbc_exec($conn_general, $sql_FullName);
while($FullName_row = odbc_fetch_array($sql_run_FullName)){
$IndivIndivId = $FullName_row['IndivId'];
$IndivTenantNdx = $FullName_row['TenantNdx'];
$IndivFirstName=$FullName_row['FirstName'];
$IndivLastName=$FullName_row['LastName'];
echo"<option value='$IndivIndivId $IndivTenantNdx'> $IndivFirstName $IndivLastName</option>";
The code above would POST the IndivId and TenantNdx (which form a composite primary key for the individuals table) to the page containing the code below which would then separate the 2 fields and search by the PK rather than the individual's name:
$IndivSurname = $_POST['IndivSurname'];
$explode_sql = explode(" ", $IndivSurname, 2);
$ListIndivId = $explode_sql['0'];
$ListTenantId = $explode_sql['1'];
in my script a "restaurant" can have multiple locations so, i made a column in the restaurant table containing a coma seperated list with locations.
Now i want to make a msql query that checks if the id can be fount is this column (comma seperated list) and if so then select it. i came up with this
SELECT restaurant_id,restaurant_name
FROM restaurant WHERE ('.$locIdList.') IN (locationRes)
ORDER BY restaurant_name ASC'
It does work... but i have some restaurants where I added location 16 and 17 so (16,17) now when i do this query for location 16 it shows the restaurant but when i dot this for location 17 it does not... but the whole point was to get the multi values from the comma seperated list.
So how to do this ?
You can use PHP to generate the query for each comma-delimited value. i.e., run a PHP loop on comma-delimited comparison string, convert it into individual items and compare each item through LIKE Operator and an IN () function.
SELECT restaurant_id,restaurant_name
FROM restaurant WHERE ('16') IN (locationRes)
OR
FROM restaurant WHERE ('17') IN (locationRes)
ORDER BY restaurant_name ASC'
The best solution would be to create a relation table that implements the many-to-many relationship between restaurants and locations. Then you can use a solution like How to return rows that have the same column values in MySql to find all the restaurants that are in all locations.
To search for a value in a comma-separated list, you use FIND_IN_SET. But this can only search for one value at a time. If you want to find restaurants that are in all locations, you need to combine multiple calls:
$locArray = explode(',', $locIdList);
$locQuery = implode(' AND ', array_map(function($loc) { return "FIND_IN_SET($loc, locationRes)"; }, $locArray));
$query = "SELECT restaurant_id,restaurant_name
FROM restaurant
WHERE $locQuery
ORDER BY restaurant_name ASC";
If you want to find restaurants that are in any of the locations instead of all locations, change AND to OR.
You should avoid putting multiple values inside a single column.
Instead, it's recommended to create another table locations(location_id, col1, col2, restaurant_id), while the restaurant_id field references to the primary key in table restaurant.
If you have a comma separated list you are pulling from a database, you could use PHP to separate the list and create an array of each item.
$result_of_sql = "restaurant 1, restaurant 2, restaurant 3, restaurant 4, restaurant 5, restaurant 6";
$restaurants = explode(',', $result_of_sql);
echo '<ul>';
foreach ($restaurants as $restaurant) {
echo '<li>' . trim($restaurant) . '</li>';
}
echo '</ul>';
What happens here is first, you pull out all of you restaurants (the comma separated list). Then you use explode to take away the commas and create an array. Then you use the foreach loop to echo the entire array out. trim is just to clean everything up by removing whitespace you might have before and after the restaurant name.
HI all,
I am trying to figure out how to put this into words even, but I am wanting to know how to format the output from each table separately in a "multiple table" mysql query. The output from the table1 "wall" is formatted within a while loop, but the content from table2 "actions" is already formatted(as 1 line of text with links) before it is inserted into the table(column action_body), so inside the loop I would only be outputting the action_date and action_body columns from the actions table.
I am probably not using the correct sql method(if Im doing anything right at all, that is) for the results I need, so feel free to correct my novice example, or suggest a new way to approach this.
Query:
$query = "SELECT wall.wall_id, wall.wall_owner_id, wall.wall_user_id,
wall.wall_post_date, wall.wall_post_content, actions.action_id,
actions.action_date, actions.action_user_id, actions.action_title,
actions.action_body FROM wall, actions
ORDER BY wall.wall_post_date, actions.action_date DESC";
$result = mysql_query($query);
while( $rows = mysql_fetch_assoc($result) {
// What to put here
}
Any help is appreciated, thanks, Lea
Update after comments
SELECT w.* FROM (
(SELECT
'w' as type,
wall_id as id,
wall_owner_id as owner_id,
wall_user_id as user_id,
wall_post_date as post_date,
NULL as title,
wall_post_content as content
FROM wall
WHERE wall_owner_id = x # user id of owner
)
UNION
(SELECT
'a' as type,
action_id as id,
action_user_id as owner_id,
NULL as user_id,
action_post_date as post_date,
action_title as title,
action_body as content
FROM actions
WHERE action_user_id = x # user id of owner
)
) w
ORDER BY w.post_date DESC
Because you don't JOIN on a specific field, you're gonna get every row-row combination of the two tables, which is a whole lot more data than you probably want.
You'd be better of by doing 2 queries, one for each table. While looping through the result of each table, you can collect the data you want in one array, with the field you want to sort it by as array key.
Then you sort the array, and loop through it to print it out.