Drupal-based SQL query through PHP: count t1 join t2 - php

I have two tables like so:
table {node}
`nid`, `uid`, `type`
1 1 basketball
2 1 basketball
3 1 football
4 2 football
5 2 basketball
table {strato_ticket}
`tid`, `author_uid`, `purpose`, `active`
1 1 'Ticket to a basketball game' TRUE
2 1 'Ticket to a football game' TRUE
3 2 'Ticket to a football game' FALSE
I'd like to generate a report that counts the number of each kind of node, and then counts the number of active tickets that each user has associated with that kind of node.
My solution uses a combination of SQL and PHP: I have a PHP loop for each kind of node that I'm interested in, which simplifies the SQL query, and translates from 'type' to 'purpose', eg
$node_types = array('basketball', 'football');
foreach($node_types as $node){
switch($type){
case 'basketball':
$purpose = array('Ticket to a basketball node');
break;
case 'football':
$purpose = array('Ticket to a football game');
break;
}
$where = " WHERE ({strato_ticket}.`purpose` = '"
.implode("' OR {strato_ticket}.`purpose` = '",$purpose)."')";
Finally I have the trouble spot, the SQL query. When I was just counting nodes owned by each user, it worked fine:
$query = "
SELECT uid, count( * ) AS nodes_owned
FROM {node} WHERE `type` = '$type'
GROUP BY uid ORDER BY nodes_owned DESC
";
$query = db_query($query);
output:
Now displaying info for basketball.
uid nodes_owned
1 2
2 1
Now displaying info for football.
uid nodes_owned
1 1
2 1
But now that I need to query against another table, strato_ticket, things get complicated, and my query is returning FALSE without throwing an error (I think).
$query = "
SELECT count(*) as tickets
FROM {strato_ticket} INNER JOIN (
SELECT node.uid, count( * ) AS nodes_owned
FROM {node} WHERE `type` = '$type'
GROUP BY uid
) AS {nodecount}
ON {strato_ticket}.`author_uid` = {nodecount}.`uid`
$where
GROUP BY nodecount.uid ORDER BY nodecount.nodes_owned DESC
";
$query = db_query($query);
I'm not very good with SQL and I'm not quite sure how it's broken. Could use a little help?
Ideally would like to see
uid nodes_owned tickets
//basketball
1 2 1
2 1 0
//football
1 1 1
2 1 0

Aside from the placeholders, which I can get to later, I think this solves it.
$form = array();
$node_types = array('basketball','football');
// if($user->uid == 1){
$form[$type][] = array('#value'=>"Showing how many of each node type each user owns.".'<br/>');
foreach($node_types as $type){
// Count the number of nodes each user owns of $type.
$form[$type][] = array('#value'=>"Now displaying info for $type".'s. <br/>');
switch($type){
case 'basketball':
$purpose = array('ticket to a basketball game', 'basketball');
break;
case 'football':
$purpose = array('ticket to a football game');
break;
}
$purpose = implode("', '", $purpose);
//#todo : Make a temporary table to query against so I'm not hitting node table multiple times.
$ticketquery = "
SELECT author_uid, purpose, COUNT( * ) AS invitees_accepted
FROM {strato_ticket}
WHERE purpose IN ('$purpose')
GROUP BY author_uid, `purpose`
";
$nodequery = "
SELECT node.uid, count( * ) AS nodes_owned, type
FROM {node}
WHERE `type` IN ('$type')
GROUP BY uid, type";
$query = "
SELECT * FROM
($nodequery) AS nt
JOIN
($ticketquery) AS tt
ON nt.uid = tt.author_uid
GROUP BY nt.uid ORDER BY nt.nodes_owned DESC
";
drupal_set_message('Query is <br/>'.$query);
//return;
$query = db_query($query);
$first = true;
while ($rec = db_fetch_object($query)){
if($first){
$form[$type][] = array('#value'=>"And the winner is: ".print_r($rec, true).'<br/>');
$first = false;
}
else {
$form[$type][] = array('#value'=>print_r($rec, true).'<br/>');
}
}
// }
}

Related

From PHP how to efficiently execute this search in SQL Server?

I have a database structure something like the following:
Table A: PersonId, GroupId
Table B: GroupId, ParentGroupId
Given a PersonId, I want to find the Ids of all people in parent groups of that person's group.
First I select the ParentGroupId for the given PersonId, by joining with B. Then I do a while loop, selecting and recording the PersonId from A based on the GroupId returned in the previous search, and continue the loop by obtaining the next ParentGroupId from B.
Is this an efficient way to do this search, or is there an option that does not involve a while to "bubble up" in this manner?
(this is a simplified version of the actual scenario, changing the schema is not an option)
$sql = 'SELECT ParentGroupID FROM A WHERE PersonId = ' . $id;
$result = $db->query($sql);
$row = $db->fetch_array($result);
$parent_group = $row['ParentGroupId'];
if(!is_null($parent_group)) {
$parent_ids = array();
while($parent_group > 0) {
//is there a way to do this where I retrieve all managers <= lvl 6 at once, so I don't have to loop in order to 'tier up'?
$sql = 'SELECT ParentGroupID, PersonID
FROM B
INNER JOIN A on ParentGroupID = A.GroupID
WHERE ParentGroupID = ' . $parent_group;
$result = $db->query($sql);
$row = $db->fetch_array($result);
$parent_group = $row['ParentGroupID'];
$parent_ids[] = $row['PersonID'];
}
}
Combining your two queries into one would be more efficient:
$sql = 'SELECT ParentGroupID, PersonID
FROM B
INNER JOIN A on ParentGroupID = A.GroupID
WHERE ParentGroupID IN (
SELECT ParentGroupID FROM A WHERE ParentGroupID > 0
AND PersonId = ' . $id .')' ;

MYSQL - Select multiple rows in one query

claimId is foreign key
Table (statusTable)
Id_ _chaseStatus_ _claimId_
1 Open CL001
2 Close CL002
3 Open CL001
4 Open CL003
5 Open CL001
6 Open CL003
$query = "SELECT * FROM statusTable ";
$query .= "WHERE (`chaseStatus` = 'Open') ";
$query .= "AND (id = (SELECT MAX(id) FROM statusTable))";
while($row = mysqli_fetch_assoc($result)){
$items[] = $row;
}
//$items = array_reverse($items ,true);
foreach($items as $item){
$claimId = $item["claimId"];
echo $claimId;
}
My query gives me only one column which is highest id.
But I am trying to get only 'Open' from 'chaseStatus' for each 'claimId' (with highest id) like;
How can I get like this
for id = 5 : CL001
AND
for id = 6 : CL003
Any ideas?
You can retrieve the highest id of the claimid using group by.
$query = "SELECT max(Id) as Id,claimId FROM statusTable ";
$query .= "WHERE (`chaseStatus` = 'Open') ";
$query .= "GROUP BY claimId";
THis should result in the following table
Id claimId
5 CL001
6 CL003
Here's a SQL Fiddle: http://sqlfiddle.com/#!2/b000e/1
You can do what you want by including the 'Open' condition in the subquery:
SELECT *
FROM statusTable
WHERE `chaseStatus` = 'Open' AND
id IN (SELECT MAX(id) FROM statusTable WHERE chaseStatus = 'Open' GROUP By ClaimId);
I think it is redundant to have the open condition in the outer query, so this should work for you:
SELECT *
FROM statusTable
WHERE id IN (SELECT MAX(id) FROM statusTable WHERE chaseStatus = 'Open' GROUP BY ClaimId);

Is there an efficient way to search variable parameters in mySQL with different results?

I have quite a complex question and due to the specifications I've had no luck finding any help with this. Scratching my head for a few months.
I have multiple parameters however in this question I'll focus on only 3
Category ($cat)
Subcategory ($sub)
Genre ($gen)
MySQL columns:
id | category | subcategory | genre | account | date_received | date_modified
(Account is assigned: 1-3)
I would like the results to return:
if only Category is offered:
first the row account = 1, then date_received, followed by date_modified (give no preference to accounts 2 & 3)
if only Category AND Subcategory is offered:
first the row account = 1 and account = 2, then date_received, followed by date_modified (give no preference to account 3)
if only Category AND Subcategory AND genre is offered:
first the row account = 1 and account = 2 and account = 3, then date_received, followed by date_modified
So far I have this:
if ($cat AND empty($sub) AND empty($gen)) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat')
ORDER BY case when account = '1' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC ");
} else if ($cat AND $sub AND empty($gen)) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat' AND subcategory='$sub')
ORDER BY case when account = '2' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC
");
} else if ($cat AND $sub AND $gen) {
$run = mysql_query("SELECT *
FROM db
WHERE (category='$cat' AND subcategory='$sub' AND genre='$gen')
ORDER BY case when account = '3' then 1 else 2 end,
GREATEST(date_received, modified_date, account) DESC
"); }
Is there an efficient way of combing these and echoing the different results?
It feels really messy.
Many thanks everyone for any tips you can offer.
Put all the conditions in an array, and the preferred account in a variable.
$conds = array();
if ($cat) {
$account = 1;
$conds[] = "category = '$cat'";
}
if ($sub) {
$account = 2;
$conds[] = "subcategory = '$sub'";
}
if ($gen) {
$account = 3;
$conds[] = "genre = '$gen'";
}
if (!empty($conds)) {
$cond_str = implode(' AND ', $conds);
$sql = "SELECT *
FROM db
WHERE $cond_str
ORDER BY IF(account = $account, 1, 2),
GREATEST(date_received, modified_date, account) DESC";
$run = mysql_query($sql);
...
}

How get all two array values using select query at once

I want to get Name and corresponding Score at the latest time. So I tried:
$queryObj = mysql_query("SELECT `Name`,`Score` from `Table`.`Score` where `Date` = ( SELECT max(`Date`) from `Table`.`Score`) and `Name`<>'' ");
then get value from it by:
while( $obj = mysql_fetch_object( $queryObj ) ) {
$data = array();
$data['Name'] = $obj->Name;
$data['Score'] = $obj->Score;
$searches[] = $data;
}
But when I print :
print_r(array_values($searches));
the first value is missing in the array, so that won't be the right way.
I also tried:
$row = mysql_fetch_assoc($queryObj);
for ($i = 0; $i <3; $i++)
print( $row['Name'][$i]." Score: ".$row['Score'][$i]."<br />\n");
But it won't give me the right results also. How do I get the value from that query? (the query is correct, I tested it). Any body has suggestion ?
Edit: I add my sample data here:
Name Score Date
abc 3 2013-08-29 10:11:47
abc 2 2013-08-29 09:39:23
abc 1 2013-08-28 10:22:28
jane 2 2013-08-29 09:39:23
2013-08-29 10:08:36
jane 1 2013-08-29 10:11:47
tarzan 1 2013-08-29 10:11:47
Note: Yes, there is some blank values.
My expected result would be:
abc score 3
jane score 1
tarzan score 1
Ok, so after you have updated your question and provided what you expect, your query should look like this:
SELECT t1.Name, t1.Score
FROM Table.Score t1
INNER JOIN
(
SELECT max(Date) MaxDate, Name, Score
FROM Table.Score
WHERE Name <> ''
GROUP BY Name
) t2
ON t1.Name = t2.Name AND t1.Date = t2.MaxDate
This will give you pairs of Name and Score for each Name with Score based on his latest Date (1 row per Name).
So replace your original query with mine in this line:
$queryObj = mysql_query(" ... ");
Then:
$rows = array();
while($row = mysql_fetch_assoc($queryObj)) {
$rows[$row['Name']] = $row['Score'];
}
And you can nicely foreach it in the exact way you wanted in your last comment:
foreach($rows as $name => $score) {
echo $name . ' - ' . $score . "\n";
}

Using results from one MySQL query in another query in a PHP Envirnment

I have a problem, it may be a simple fix to the issue, but I can't seem to figure it out. I am new to PHP and MySQL, so I'm reading everything everywhere, but lack of experience is very frustrating, as often times it takes ages to realize a small error. Please look at the following tables and read below the questions.
The PHP/mysql is in Joomla environment, I am trying to modify a plugin, so that is updates with values from different tables into a set of other tables, that were not originally intended, but all tables reside in the same database.
Table 1 vm_orders
---------------------------------------------
order_id user_id
---------------------------------------------
20 1
55 6
65 2
30 4
50 67
Table 2 vm_order_item
---------------------------------------------
order_item_id order_id order_item_sku
---------------------------------------------
20 20 1
55 55 35
65 65 60
30 30 22
50 50 3
Table 3 xipt_ users
---------------------------------------------------
userid Profiletype template
----------------------------------------------------
1 1 default
6 3 default
2 1 default
4 8 default
67 7 default
Table 4 community_fields_values
---------------------------------------------
id user_id field_id value
---------------------------------------------
1 1 55 Female
2 6 35 Cat
3 2 2 2
4 4 18 Texas
5 67 12 bike
What I need to is first of all get the order number according to the user that has place the order.
The userid variable is being passed from elsewhere in the script. That part is working fine.
So the user 67 has placed an order. These are the things I want to achieve.
Query 1: I want to get the "orderid" value from "order_id" column of vm_orders table (table 1); i will call the result "vmorderid" and use it in another query.
Query 2: Using the "vmorderid" from query 1 as the order_id value in the "order_id" column of vm_order_item table (table 2).
I want to get the order_item_sku value from the "order_item_sku" column of my_order_item table (table 2).
I will call the result "vmsku" and use it in another query.
Query 3: Using the "vmsku" from query 2 as the profiletype value in the "Profiletype" column of vm_users table (table 3).
I want to UPDATE the value of the "profiletype" column, with "vmsku" value.
Query 4: Using the "vmsku" from query 2 as the value in the "value" column of community_fields_values (table 4).
I want to UPDATE the value of the "value" column in my_fields_values (table 4) "vmsku" value.
Okay, I hope you are with me so far, I have tried a couple of queries, but it's not working.
Here is what I have so far:
Assuming the user it is being passed from a param field.
$userid = $this->params->get('userid', 'defaultValue');
function _vm_custom_order($vmorderId)
{
$vmorderId = $database->loadResult();
$database = JFactory::getDBO();
// query the db to see if the user is already a member of group
$vmorderId ="
SELECT MAX
`order_id`
FROM
#__vm_orders';
WHERE
`user_id` = '{$userid}'
";
$database->setQuery( $vmorderId );
$data = $database->loadResult();
return $data;
}
function _vm_sku($vmsku)
{
$vmsku = $database->loadResult();
$database = JFactory::getDBO();
// query the db to see if the user is already a member of group
$vmsku = "
SELECT
`product_sku`
FROM
#__vm_order_item';
WHERE
`order_id` = '{$vmorderId}'
";
$database->setQuery( $vmsku );
$data = $database->loadResult();
return $data;
}
function _add( $userid, $groupid, $vmsku)
{
$success = false;
$database = JFactory::getDBO();
if (!$allow_multiplegroups = $this->params->get( 'allow_multiplegroups', '1' )) {
// query the db to see if the user is already a member of ANY group
$database->setQuery("
SELECT
`profiletype`
FROM
#__xipt_users
WHERE
`userid` = '{$userid}'
");
$member = $database->loadResult();
// if so, do not execute
if (intval($member) > 0) {
return $success;
}
}
$already = plgAmbrasubsAddToXipt::_already( $userid, $groupid );
if (($already != $userid))
{
$database->setQuery("
SELECT MAX
`order_id`
FROM
#__vm_orders
WHERE
`user_id` = '{$userid}'
");
$vmorderId = $database->loadResult();
if ($database->query()) {
$success = true;
}
}
if (($already != $userid))
{
$database->setQuery("
SELECT
`product_sku`
FROM
#__vm_order_item
WHERE
`order_id` = '{$vmorderId}'
");
$vmsku = $database->loadResult();
if ($database->query()) {
$success = true;
}
}
// if they aren't already a member of the group, add them to the group
if (($already != $userid))
{
$database->setQuery("
UPDATE
#__xipt_users
SET
`profiletype` = '{$vmsku}'
WHERE
`userid` = '{$userid}'
LIMIT 1
");
if ($database->query()) {
$success = true;
}
}
return $success;
}
}
I also tried it this way:
function _add( $userid, $groupid, $vmsku)
{
$success = false;
$database = JFactory::getDBO();
if (!$allow_multiplegroups = $this->params->get( 'allow_multiplegroups', '1' )) {
// query the db to see if the user is already a member of ANY group
$database->setQuery("
SELECT
`profiletype`
FROM
#__xipt_users
WHERE
`userid` = '{$userid}'
");
$member = $database->loadResult();
// if so, do not execute
if (intval($member) > 0) {
return $success;
}
}
$already = plgAmbrasubsAddToXipt::_already( $userid, $groupid );
if (($already != $userid))
{
$database->setQuery("
SELECT MAX
`order_id`
FROM
#__vm_orders
WHERE
`user_id` = '{$userid}'
");
$vmorderId = $database->loadResult();
if ($database->query()) {
$success = true;
}
}
if (($already != $userid))
{
$database->setQuery("
SELECT
`product_sku`
FROM
#__vm_order_item
WHERE
`order_id` = '{$vmorderId}'
");
$vmsku = $database->loadResult();
if ($database->query()) {
$success = true;
}
}
// if they aren't already a member of the group, add them to the group
if (($already != $userid))
{
$database->setQuery("
UPDATE
#__xipt_users
SET
`profiletype` = '{$vmsku}'
WHERE
`userid` = '{$userid}'
LIMIT 1
");
if ($database->query()) {
$success = true;
}
}
return $success;
}
}
EDIT: I have now tried as suggested, to use JOIN to accomplish the task, so far no joy!
UPDATE
#__xipt_users
SET
`profiletype.#__xipt_users` = `product_sku.#__vmsku`
WHERE
`userid` = '{$userid}'
AND
(
SELECT `order_id.#__vm_orders`
FROM #__vm_orders, #__vm_order_item
LEFT JOIN #__vm_orders
ON #__vm_orders.`order_id` = #__vm_order_item.`order_id`
ORDER BY `order_id.#__vm_order` DESC LIMIT 1
WHERE
`user_id.#__vm_orders` = '{$userid}'
) AS #__vmorder_id
SELECT ` product_sku.#__vm_order_item`
FROM #__vm_order_item, #__vmorder_id
LEFT JOIN #__vm_order_item
ON `#__vm_order_item.order_id` = `#__vmorder_id.order_id`
WHERE
`order_id.#__vm_order_item` = `order_id.#__vmorder_id`
)
AS #__vmsku
LIMIT 1
");
Join Statements
I would suggest you start learning how to create Join Statements in MySQL.
Have a look at this website:
http://www.keithjbrown.co.uk/vworks/mysql/mysql_p5.php
That way you are able to combine multiple queries into one. It will make this job a lot easier!
Piece of paper
Also it will help you to draw your database on a piece of paper to get a better overview of what you want to do. For example you can draw lines between the table fields you want to link.

Categories