I have a MySQL query that will be converted to JSON and used in Obj C for each user with a specific id. I believe that this is a MySQL puzzle, but there may be an answer in JSON. I don't ask many questions, so I'll try to make it concise.
Here is a screen shot of values for one user. If you notice, the field_id may vary because not all info is required, so the id field will vary from 3 to 8 values for a given user_id:
I have to make a query where the results GROUP BY column1 (user_id), but only WHERE column2 (field_id) has the following values field_id='18' and field='19', Then (THE BIG PROBLEM) I need to populate the results in one GROUP with both values of column3 (value) so I can get results in one JSON object.
I already know how to convert to JSON for use in iOS, but I can only get it to give me results as two objects.
My current query
$query = "SELECT * FROM table1 WHERE field_id='18' OR field_id='19' ORDER BY user_id ";
Current Result
[{"id":"5","user_id":"461","field_id":"18","value":"1_MX4zNjcxNzM5Mn4x...","access":"0"},
{"id":"6","user_id":"461","field_id":"19","value":"T1==cGFydG5lcl9pZD0...","access":"0"},
{"id":"11","user_id":"463","field_id":"18","value":"1_MX4zNjcxNzM...","access":"0"},
{"id":"12","user_id":"463","field_id":"19","value":"T1==cGFydG5lcl9...","access":"0"}]
I need the two JSON objects with matching user_id fields as one object with results that differentiate field='18' value from field='19' value. Something like:
[{"id":"5","user_id":"461","field_id":"18","value18":"1_MX4zNjcxNzM5Mn4x...","value19":"T1==cGFydG5lcl9pZD0...","access":"0"},
{"id":"11","user_id":"463","field_id":"18","value18":"1_MX4zNjcxNzM...","value19":"T1==cGFydG5lcl9...","access":"0"}]
OR
[{"id":"5","user_id":"461","field_id='18'":"1_MX4zNjcxNzM5Mn4x...","field='19'":"T1==cGFydG5lcl9pZD0...","access":"0"},
{"id":"11","user_id":"463","field_id='18'":"1_MX4zNjcxNzM...","field='19'":"T1==cGFydG5lcl9...","access":"0"}]
THANKS...
I'm not 100% sure if this will work. I cannot easily try the JSON output of it. But what if you run a query like this?
SELECT id, user_id,
GROUP_CONCAT(field_id,':',value) field_id,
access
FROM table1 WHERE field_id='18' OR field_id='19'
GROUP BY user_id
ORDER BY user_id
You probably want to to look at handling this in PHP when reading in the result set.
So use your current query of
SELECT * FROM table1 WHERE field_id='18' OR field_id='19' ORDER BY user_id
But build result data object like this:
$results = array();
$i = -1;
$current_user_id = '';
while ($row = [YOUR MySQL FETCH MECHANISM HERE]) {
// determine if this record represents a new user id in the result set
// if so, we need to set up the user object and start another entry in top level array
if($current_user_id != $row['user_id']) {
// you have moved to a new user in the result set
// increment your array counter and set current user id
$i++; // will set value to 0 on first iteration
$current_user_id = $row['user_id'];
// build new array entry
$results[$i] = new stdClass();
$results[$i]->user_id = $current_user_id;
$results[$i]->fields = array();
}
// build field object for insertion
$field = new stdClass();
$field->field_id = $row['field_id'];
$field->value = $row['value'];
$results[$i]->fields[] = $field;
}
On encoding $results this would give you a JSON structure like this:
[
{
"user_id":"461",
"fields": [
{
"field_id":"18",
"value":"foobar"
},
{
"field_id":"19",
"value":"abcxyz"
}
]
},
...
]
This data structure is going to be more readily usable by consuming app than some solution which requires exploding concatenated field id/value strings. Also note that I have not included id field anywhere in data structure, as it has no meaning in this context. If you truly needed that id, you could add it as another property in the field object since that is where there is a one-to-one relationship (not with user_id).
Based on your comment, if the field value is known and you need to access it via field_id index, you can slightly modify what I have shown above to build index-able field listing rather than a simply array of objects:
$results = array();
$i = -1;
$current_user_id = '';
while ($row = [YOUR MySQL FETCH MECHANISM HERE]) {
// determine if this record represents a new user id in the result set
// if so, we need to set up the user object and start another entry in top level array
if($current_user_id != $row['user_id']) {
// you have moved to a new user in the result set
// increment your array counter and set current user id
$i++; // will set value to 0 on first iteration
$current_user_id = $row['user_id'];
// build new array entry
$results[$i] = new stdClass();
$results[$i]->user_id = $current_user_id;
$results[$i]->fields = array();
}
// insert field value at field_id index position
$results[$i]->fields[$row['field_id']] = $row['value'];
}
This would give you a JSON representation like this.
[
{
"user_id":"461",
"fields": {
"18":"foobar",
"19":"abcxyz"
}
},
...
]
This would allow easy look-up by client based on field id. Of course you may want to consider similar for user_id. From the user object you could just access fields->18 (or similar based on on client language syntax).
Related
So I was trying to make a "create new user" function in PHP which should basically check in the database which is the lowest possible ID to assign to that new user. But I have now tried around with so many different methods and they all do not work as they should. Here is my current version:
function newUser($connection) {
$notNewId = sqlsrv_query ($connection, "SELECT id FROM users"); //get id from users table
while($notNewId2 = sqlsrv_fetch_array ($notNewId)) {
for ($i = 0; $i <= sizeOf($notNewId2); $i++) {
foreach ($notNewId2 as $key => $value ) {
if ($i != $value) {
break;
}
}
}
$id = $i;
return $id;
}
}
the $connection is a element of type sqlsrv_connect.
as far as I can tell my current version should be able to read the ids and put them in an array, but from there on something went wrong. As well... I may have to sort the array after id, but I have no clue how to do that.
I would really appreciate any help, even if it's no actual code and just the logic explained, thx.
EDIT: Seems like it is not clear enough, what I want. My script should assign a new ID to the new row in the users table, if that is possible automatically somehow with SQL, then please explain to me how. (Right now ID is not a primary key, I will change that as soon as I can)
Taking the highest number and adding one is not enough (like when I have 0, 1, 2, 4 and 5, the new ID should be 3, not 6). But still thanks, I didn't knew about that MAX thing.
Assuming id is your primary key and you're not trying to auto increment it in your users table, you can find the maximum value of it and add 1 in your SQL query. This mitigates the need for your nested for loops. Use ISNULL to check if that value is not null and default to 1 otherwise.
function newUser($connection) {
$query = sqlsrv_query ($connection, "SELECT ISNULL(MAX(id)+1, 1) FROM users");
return sqlsrv_fetch($query);
}
I have a postgres table with four columns labelled dstart which is date data type,
dend which is also a date data type, dcontract which is a date data type and id which is a integer. I am trying to run a php code to get the data using an array and use it in the body of my application. But when I test the array and try to echo some values... My browser just displays the word array... Is there anyway I can be able to retrieve the data or fix this code? Please see code below
<?php
function getLiveDate($campid)
{
global $conn,$agencies;
$return=array(
'livedate'=>'',
'campid'=>'',
'enddate'=>'',
'dateContract'=>'',
);
$sql = "SELECT id, dcontract, dstart, dend
FROM campaigns
WHERE id = '".$campid."' ORDER BY dstart DESC LIMIT 1";
$r = pg_query($conn,$sql);
if ($r)
{
$d = pg_fetch_array($r);
if (!empty($d))
{
$return['livedate'] = $d['dstart'];
$return['campid'] = $d['id'];
$return['enddate'] = $d['dend'];
$return['dateContract'] = $d['dcontract'];
}
}
#pg_free_result($r);
return $return;
}
I am pretty sure, your array $d is "multi-dimensional" and pg_fetch_array() returns an array of arrays, because the result of SQL queries in general may contain multiple rows. You limited it to one row, but you certainly get the correct values by assinging $return['livedata'] = $d[0]['dstart']; or $return['livedata'] = $d['dstart'][0]; and so on (I am not familiar with that particularly function for I usually use MySQL instead of Postgre).
Besides, try echoing your data by means of print_r() instead of echo.
The $return variable is an array, if you want shows the content, you must use print_r or var_dump not echo.
I have a little problem to code in PHP how to obtain this result with data provided from MySQL
{"profiles":[
{"ID": "39780b57-9181-4a41-a31e-5d4b3fa59a50", "Name": "Mihai - BP Dev Team","CountryCode": "ro","PictureID": "a30d750a-38e6-407f-a722-943fe3711807","IsStandard": true,"IsOnline": true,"IsPremium": true,"IsVerified": true,"Age": 27,"CityStateCode": "Bucharest"},
{"ID": "e1dd5bab-1eeb-4729-a4f6-0baeb851f750", "Name": "Nicolai", "CountryCode": "dk", "PictureID": "af1345b5-8380-4300-abf0-1d5f15c90040", "IsStandard": true, "Age": 32, "CityStateCode": "Valby"},
{"ID": "2c8535ec-25a4-4a3e-a333-c3797aff491f", "Name": "Testing", "CountryCode": "ca", "PictureID": "ba44bf9b-1592-40a8-b60c-068603bfb9c1", "IsStandard": true, "Age": 30, "CityStateCode": "Centre-Sud North"}}
]}
This is my PHP code :
$accessDb = new Connexion("gaiurba_MyBD");
$connexion2 = $accessDb->openConnexion();
if ($query2 = $connexion2->prepare("SELECT u.UserName as UserName, u.PictureID as PictureID, u.CountryCode as CountryCode,
u.DateOfBirth as DateOfBirth, u.CityCode as CityCode, u.VerifiedTimestamp as VerifiedTimestamp,
u.OnlineStatus as OnlineStatus, u.IsPaying as IsPaying, u.StatusAvailableForDates as StatusAvailableForDates,
cc.$languageCode as CityStateCode, os.$languageCode as LabelOnlineStatus
FROM Users u
INNER JOIN CityCode cc ON u.CityCode = cc.id
INNER JOIN OnlineStatus os ON u.OnlineStatus = os.id
WHERE u.ID = ?")) {
$query2->bind_param('s', $id);
$query2->execute();
$query2->bind_result($UserName, $PictureID, $CountryCode, $DateOfBirth, $CityStateCode, $VerifiedTimestamp, $OnlineStatus, $IsPaying, $StatusAvailableForDates, $CityStateCode, $LabelOnlineStatus);
$query2->store_result();
$affected2 = $connexion2->affected_rows;
// TRACE
echo "[affected2 row 2 = $affected2]";
if ($affected2 == 1) {
while ($query2->fetch()) {
echo "[ID = $id - UserName = $UserName - PictureID = $PictureID - CountryCode = $CountryCode - DateOfBirth = $DateOfBirth - CityStateCode = $CityStateCode - VerifiedTimestamp = $VerifiedTimestamp - OnlineStatus = $OnlineStatus - IsPaying = $IsPaying - StatusAvailableForDates = $StatusAvailableForDates - CityStateCode = $CityStateCode - LabelOnlineStatus = $LabelOnlineStatus]";
}
} else {
$result = '{"exception":false,"success":false,"status":0,"message":"ERROR SQL Query : SELECT-ULL-ID Number of row !","confirmMessage":null,"html":null,"data":null}';
}
} else {
$result = '{"exception":false,"success":false,"status":0,"message":"ERROR SQL Query : SELECT-ULL-ID Number of row !","confirmMessage":null,"html":null,"data":null}';
}
I know the right code is on my while($query2->fetch()) condition because my echo see me good information read from my BD. The first thing i need to create an array in PHP and append each row fetched from BD and at the end use
echo json_encode($result);
Do not pay attention to my data return by me SELECT and the data in the JSON string. I know I'll have to format some data in my while loop to get the right result.
I just need to know how to create an array in which I add a new array for each rows returned by MySQL.
Thank you for your helping !
Creating an array is as simple as:
$profiles = array();
or just
// Add an item. Array is created if $x didn't contain an array already.
$profiles[] = 'foo';
So to create something with the structure you like, you'll need an object with a property that contains an array of objects representing the rows.
You can create a simple object in a similar fashion as arrays: just start assigning properties. So to create the array of profiles, just do this for each row:
$profile = null;
$profile->UserName = $UserName;
$profile->PictureID = $PictureID;
// Etc
Maybe your database class supports a method to return an entire row as an object instead of calling fetch() combined with outbound parameters. That way you don't need to create the object yourself, saving a couple of lines.
// Add profile object to array.
$profiles[] := $profile;
Maybe your database class supports a way to return the entire dataset as an array of objects. If so, you don't need to loop and build the array yourself. Saving yet another couple of lines of code.
However you have built the array, afterwards, wrap it in another object, in its profiles property to be precise.
$result = null;
$result->profiles = $profiles;
And output:
echo json_encode($result);
It's not strictly necessary to make a variable null before starting to assign properties, but it prevents accidental reuse of an old variable. Especially in the loop this is required, otherwise you'll just reassign the properties of the same object and add the same object a number of times to the array, leading to undesired results (every row being the same).
Instead of just assigning properties, you can actually create an object before doing so:
$profile = new StdClass();
This is a little more verbose and therefor maybe a little more readable, just as using array() to initialize an empty array. It's a matter of personal taste.
Is there a way to join two arrays based upon a same value in a key?
As an example in MySQL you can left join two tables when two fields have the same value in it.
The first array called 'phoneArr' is one with a person_id and a phone number
The second array called 'clientDate' is one with a person_id and a appointment date.
Here are the arrays:
$phoneArr = array();
$phoneArr[0]['person_id'] = "123456";
$phoneArr[0]['phone'] = "555-2222";
$phoneArr[1]['person_id'] = "7654321";
$phoneArr[1]['phone'] = "555-1111";
$clientDate = array();
$clientDate[0]['person_id'] = "123456";
$clientDate[0]['date_time'] = "01-07-13 13:00";
$clientDate[1]['person_id'] = "7654321";
$clientDate[1]['date_time'] = "01-07-13 10:30";
Now if the person id in clientDate will always exist in the phoneArr, but not the other wat around. The persons in the phoneArr do not always exist in the clientDate.
What I want is to get a match of these arrays where I will be left with a new array with the info of both arrays, but only of there is a match on the 'person_id'.
Is this doable without MySQL?
If you are going to look up data by a key value, and that key value is unique over the table, you might consider using that as the array key, so your $phoneArr would be set up as:
$phoneArr["123456"]['phone'] = "555-2222";
$phoneArr["7654321"]['phone'] = "555-1111";
Do the same with the other array
Then you can:
foreach ($phoneArr AS $id=>$record) {
if (array_key_exists($id,$clientDate)) {
// the client id is $id, $record has their phone #, and $clientDate[$id] has their date/time
// do something with it here - either process it (preferable) or put the data in another array.
}
}
I have two dynamic tables (tabx and taby) which are created and maintained through a php interface where columns can be added, deleted, renamed etc.
I want to read all columns simulataneously from the two tables like so;-
select * from tabx,taby where ... ;
I want to be able to tell from the result of the query whether each column came from either tabx or taby - is there a way to force mysql to return fully qualified column names e.g. tabx.col1, tabx.col2, taby.coln etc?
In PHP, you can get the field information from the result, like so (stolen from a project I wrote long ago):
/*
Similar to mysql_fetch_assoc(), this function returns an associative array
given a mysql resource, but prepends the table name (or table alias, if
used in the query) to the column name, effectively namespacing the column
names and allowing SELECTS for column names that would otherwise have collided
when building a row's associative array.
*/
function mysql_fetch_assoc_with_table_names($resource) {
// get a numerically indexed row, which includes all fields, even if their names collide
$row = mysql_fetch_row($resource);
if( ! $row)
return $row;
$result = array();
$size = count($row);
for($i = 0; $i < $size; $i++) {
// now fetch the field information
$info = mysql_fetch_field($resource, $i);
$table = $info->table;
$name = $info->name;
// and make an associative array, where the key is $table.$name
$result["$table.$name"] = $row[$i]; // e.g. $result["user.name"] = "Joe Schmoe";
}
return $result;
}
Then you can use it like this:
$resource = mysql_query("SELECT * FROM user JOIN question USING (user_id)");
while($row = mysql_fetch_assoc_with_table_names($resource)) {
echo $row['question.title'] . ' Asked by ' . $row['user.name'] . "\n";
}
So to answer your question directly, the table name data is always sent by MySQL -- It's up to the client to tell you where each column came from. If you really want MySQL to return each column name unambiguously, you will need to modify your queries to do the aliasing explicitly, like #Shabbyrobe suggested.
select * from tabx tx, taby ty where ... ;
Does:
SELECT tabx.*, taby.* FROM tabx, taby WHERE ...
work?
I'm left wondering what you are trying to accomplish. First of all, adding and removing columns from a table is a strange practice; it implies that the schema of your data is changing at run-time.
Furthermore, to query from the two tables at the same time, there should be some kind of relationship between them. Rows in one table should be correlated in some way with rows of the other table. If this is not the case, you're better off doing two separate SELECT queries.
The answer to your question has already been given: SELECT tablename.* to retrieve all the columns from the given table. This may or may not work correctly if there are columns with the same name in both tables; you should look that up in the documentation.
Could you give us more information on the problem you're trying to solve? I think there's a good chance you're going about this the wrong way.
Leaving aside any questions about why you might want to do this, and why you would want to do a cross join here at all, here's the best way I can come up with off the top of my head.
You could try doing an EXPLAIN on each table and build the select statement programatically from the result. Here's a poor example of a script which will give you a dynamically generated field list with aliases. This will increase the number of queries you perform though as each table in the dynamically generated query will cause an EXPLAIN query to be fired (although this could be mitigated with caching fairly easily).
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
function aliasFields($pdo, $table, $delim='__') {
$fields = array();
// gotta sanitise the table name - can't do it with prepared statement
$table = preg_replace('/[^A-z0-9_]/', "", $table);
foreach ($pdo->query("EXPLAIN `".$table."`") as $row) {
$fields[] = $table.'.'.$row['Field'].' as '.$table.$delim.$row['Field'];
}
return $fields;
}
$fieldAliases = array_merge(aliasFields($pdo, 'artist'), aliasFields($pdo, 'event'));
$query = 'SELECT '.implode(', ', $fieldAliases).' FROM artist, event';
echo $query;
The result is a query that looks like this, with the table and column name separated by two underscores (or whatever delimeter you like, see the third parameter to aliasFields()):
// ABOVE PROGRAM'S OUTPUT (assuming database exists)
SELECT artist__artist_id, artist__event_id, artist__artist_name, event__event_id, event__event_name FROM artist, event
From there, when you iterate over the results, you can just do an explode on each field name with the same delimeter to get the table name and field name.
John Douthat's answer is much better than the above. It would only be useful if the field metadata was not returned by the database, as PDO threatens may be the case with some drivers.
Here is a simple snippet for how to do what John suggetsted using PDO instead of mysql_*():
<?php
$pdo = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
$query = 'SELECT artist.*, eventartist.* FROM artist, eventartist LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute();
while ($row = $stmt->fetch()) {
foreach ($row as $key=>$value) {
if (is_int($key)) {
$meta = $stmt->getColumnMeta($key);
echo $meta['table'].".".$meta['name']."<br />";
}
}
}