How to get row count as column - php

So I have a query like this
SELECT DISTINCT colB FROM tbl WHERE colA = "foo" LIMIT 0, 20
which gets me an array with max. 20 records where colA matches "foo", but without duplicate records. Each array entry contains an associative array that contains the value of colB, like
0 => array(
'colB' => 'some_value',
),
1 => array(
'colB' => 'other_value',
)
Can I also get the COUNT() for colB value? I mean this:
SELECT COUNT() as cbCount FROM tbl WHERE colA = "foo" AND colB = "some_value"
SELECT COUNT() as cbCount FROM tbl WHERE colA = "foo" AND colB = "other_value"
But included in the first query as another array field, like:
0 => array(
'colB' => 'some_value',
'cbCount' => 5,
),
1 => array(
'colB' => 'other_value',
'cbCount' => 2,
)

You need to use Group By with Count -
SELECT
colB, count(colB) as cbCount
FROM
tbl
WHERE
colA = 'foo'
GROUP BY
colB
LIMIT
0, 20
This query will fetch the first 20 rows, group them according to the distinct values of colB and give their count.

all you need to do is to use GROUP BY clause
SELECT colB,
COUNT(colB) AS cbCount
FROM tableName
WHERE colA = 'Foo'
GROUP BY colB

Related

PDO Error Code 1060 Duplicate column name for Inserting Record to table

I tried to Insert Record to table using PDO but its always return this error Error : Array ( [0] => 42S21 [1] => 1060 [2] => Duplicate column name '' )
and Sometimes inserting perfectly. I don't understand why its happened.
$data=array(
':business_title' =>$title ,
':business_cover' => $cover,
':business_logo' => $logo,
':business_location'=>$location,
':business_address' =>$address,
':business_contact' =>$phone ,
':business_email' =>$email ,
':business_url' =>$website ,
':business_category' =>$category ,
':business_subcategory' =>$subcategory ,
':business_keywords' =>$keywords ,
':business_full_desc' => $summary,
':business_amenities' => $amenities,
':business_socialurl' => $socialurl,
':business_token' => $token,
':user_id' => $userid
);
$query = "
INSERT INTO tablename
(business_title,business_cover,business_logo,business_location,business_address,business_contact,business_email,business_url,business_category,business_subcategory,business_keywords,business_full_desc,business_amenities, business_socialurl,business_token, user_id)
SELECT * FROM (SELECT :business_title,:business_cover,:business_logo,:business_location,:business_address,:business_contact,:business_email,:business_url,:business_category,:business_subcategory,:business_keywords,:business_full_desc,:business_amenities, :business_socialurl,:business_token, :user_id) AS tmp
WHERE NOT EXISTS (
SELECT user_id FROM tablename WHERE user_id = :user_id
) LIMIT 1
";
Your problem is occurring when you get duplicated values in the input data. When you SELECT a set of constant values, MySQL automatically generates column names which match the values. For example:
SELECT 'a', 'b', 'c'
yields the result:
a b c
---------
a b c
Now if you
SELECT 'a', 'b', 'b'
You get
a b b
---------
a b b
As a result, if you then attempt to
SELECT * FROM (SELECT 'a', 'b', 'b') AS tmp;
You will get a duplicate column error as there are two columns called b in the result set of the subquery.
You can work around this by giving the values column aliases, for example:
SELECT * FROM (SELECT 'a' AS a, 'b' AS b, 'b' AS c) AS tmp;
Output:
a b c
a b b
Demo on dbfiddle
Note that it's not clear that you need the complexity of the query that you have, you should be able to simply:
INSERT INTO tablename (business_title,business_cover,business_logo,business_location,business_address,business_contact,business_email,business_url,business_category,business_subcategory,business_keywords,business_full_desc,business_amenities, business_socialurl,business_token, user_id)
SELECT :business_title,:business_cover,:business_logo,:business_location,:business_address,:business_contact,:business_email,:business_url,:business_category,:business_subcategory,:business_keywords,:business_full_desc,:business_amenities, :business_socialurl,:business_token, :user_id
WHERE NOT EXISTS (
SELECT * FROM tablename WHERE user_id = :user_id
)
See for example this demo.

I want to match rows in one table with rows in another table and each row should just be matched once

I want to match rows in one table with rows in another table and each row should just be matched once. I have constructed the below query which in all other respects works fine except that I am failing to tweak it further so that a row may only be selected once.
try{$results_pref_school1 = $db->query('SELECT mps.mps_client_ec_no, mcs.mcs_client_ec_no, mps.mps_school_id, mcs.mcs_school_id
FROM match_pref_schools AS mps
INNER JOIN match_current_schools AS mcs
ON mps.mps_school_id = mcs.mcs_school_id
AND mcs.mcs_id IN (SELECT MIN(mcs.mcs_id)
FROM match_current_schools AS mcs
GROUP BY mcs.mcs_school_id)
ORDER BY mcs.mcs_id');
}catch (Exception $e){
echo 'Failed to retrieve matched preferred school';
exit;
}
$matched_school = $results_pref_school1->fetchAll(PDO::FETCH_ASSOC);
A var_dump of $matched_school produces:
Array
(
[1] => Array
(
[mps_client_ec_no] => REG5
[mcs_client_ec_no] => GL98888
[mps_school_id] => 6
[mcs_school_id] => 6
)
[2] => Array
(
[mps_client_ec_no] => TAS4752
[mcs_client_ec_no] => ALF1252
[mps_school_id] => 14
[mcs_school_id] => 14
)
[3] => Array
(
[mps_client_ec_no] => MAP002
[mcs_client_ec_no] => ALF1252
[mps_school_id] => 14
[mcs_school_id] => 14
)
)
In the above result I wanted ALF1252 to be matched only once.
#Parts Hope this is helpful for your query
in this i added index keys for remove "Using where; Using join buffer (Block Nested Loop) ", and add one
matched rows and your query performance now is best.
QUERY:
SELECT mps.mps_client_ec_no,mps.mps_school_id, mcs.mcs_client_ec_no, mcs.mcs_school_id
FROM match_pref_schools AS mps INNER JOIN match_current_schools AS mcs
ON mps.mps_school_id = mcs.mcs_school_id
where mcs.mcs_id IN (SELECT MIN(mcs.mcs_id)
FROM match_current_schools AS mcs
GROUP BY mcs.mcs_school_id)
ORDER BY mcs.mcs_id
Index :
KEY `mcs-key` (`mcs_school_id`,`mcs_id`,`mcs_client_ec_no` )
KEY `mps-key` (`mps_school_id`,`mps_client_ec_no`)
INSERT INTO match_current_schools
(mcs_id, mcs_client_ec_no, mcs_school_id, mcs_distr_id, mcs_province_id, mcs_client_level_taught, mcs_sub1_id,
mcs_sub2_id) VALUES (6, 'XYZ', 1, 27, 3, 'HIGH SCHOOL - A LEVEL', 1,
9);
check here : http://sqlfiddle.com/#!9/c4103d/2

MYSQL php: query multiple rows and return value if "WHERE IN" id not found

I am developing a website on wordpress that manages events.
The issue is that I need to get some event title names from their corresponding IDs in a single query. I am trying to get multiple rows out of a single MYSQL query, which works fine using "WHERE IN ({$IDs})":
$events_implode = implode(',',$events);
$events_titles = $wpdb->get_results("SELECT `title` FROM `wp_events` WHERE `id` in ({$events_implode}) ORDER BY FIELD(id,{$events_implode}",ARRAY_A);
However, I need it to return a value/string if one of the $IDs was not found in the query instead of returning nothing.
Example:
If $events_implode is like: 318,185,180,377, and the events with IDs 180 & 185 do not exist (being deleted for instance), I get back the events titles for 318 & 377 only:
Array
(
[0] => Array
(
[title] => Title 1
)
[1] => Array
(
[title] => Title 4
)
)
while I need it to return something like:
Array
(
[0] => Array
(
[title] => Title 1
)
[3] => Array
(
[title] => Title 4
)
)
I tried IFNULL:
$events_titles = $wpdb->get_results("SELECT IFNULL( (SELECT `title` FROM `wp_events` WHERE `id` in ({$events_implode}) ORDER BY FIELD(id,{$events_implode}) ),'not found')",ARRAY_A);
but since the query returns more than one row, I get the error message:
"mysqli_query(): (21000/1242): Subquery returns more than 1 row"
Is there a solution to that?
Many thanks!
You could achieve this by also querying the id and not just the title:
SELECT id, title FROM ... etc
Then your result array will look like this (for the example data)
array(
0 => array("id" => 318, "title" => "title for 318"),
1 => array("id" => 377, "title" => "title for 377")
)
But this can be converted to what you need, with the help of the $events array you already have:
foreach($event_titles as $row) {
$hash[array_search($row['id'], $events)] = $row['title'];
};
$events_titles = $hash;
Now the array looks like this (for the example data):
array(
0 => array("title" => "title for 318"),
3 => array("title" => "title for 377")
)
NB: That conversion can also be done without explicit loop:
$ids = array_intersect($events, array_column($event_titles, 'id'));
$event_titles = array_combine(array_keys($ids), array_column($event_titles, 'title'));
Alternative
The above is probably the best solution for your case, but you could also build your query dynamically to achieve this:
$subsql = implode(
' UNION ALL ',
array_map(function ($event) { return "SELECT $event AS id"; }, $events)
);
$sql = "SELECT wp_events.title
FROM ($subsql) AS eid
LEFT JOIN wp_events ON wp_events.id = eid.id
ORDER BY eid.id";
$events_titles = $wpdb->get_results($sql, ARRAY_A);
The value for $subsql will be like this (for example data):
SELECT 318 AS id UNION ALL
SELECT 185 AS id UNION ALL
SELECT 180 AS id UNION ALL
SELECT 377 AS id
The value of $events_titles will be an array that has one entry for each event, whether or not it matched. So for the example you gave, you would get this result:
array(
0 => array("title" => "title for 318"),
1 => array("title" => null), // because no match with 185
2 => array("title" => null), // because no match with 180
3 => array("title" => "title for 377")
)
So you can now just test for null. If additionally you would like to remove the null entries without changing the indexes (0 ... 3) in the array, then do this:
$event_titles = array_filter($event_titles, function ($title) { return $title; });
This will give you (in the example):
array(
0 => array("title" => "title for 318"),
3 => array("title" => "title for 377")
)
Using in clause seems no possible but you can build a dinamic query using union form dual
"SELECT t.index, a.`title`
FROM `wp_events` as a
INNER JOIN ( select 1 as index , 318 as id
from dual
union
select 2, 185
from dual
union
select 3, 180
from dual
union
select 4, 377
from dual
) t on t.id = b.id
ORDER BY t.index"
No, there is no way. The returning array from the mysql-query has nothing to do with the implode-array you gave to the query. There might be options to achieve that (creating a temp-table, fill it with keys, left join from that table to the events-table), but please don't to that as it is bad practice and nut KISS (keep it simple, stupid).
The simple question is, why do you want to do that?

How to handle column default value insert in SQLIte?

Below is the table structure. Insert query and Error message.
Table Structure
CREATE TABLE d0000ke_c_name (
c_name INTEGER PRIMARY KEY NOT NULL,
value VARCHAR(255) ,
sc_version INTEGER ,
sc_state INTEGER
);
Insert Query
$sql = "INSERT INTO d0000kv_c_name SELECT 3 AS 'c_name','manash' AS 'value' UNION SELECT 2,'ram' UNION SELECT 1,'rahim'";
$statement = $this->odb->prepare($sql);
if (!$statement) {
echo "\nPDO::errorInfo():\n";
print_r($this->odb->errorInfo());
}
$statement->execute();
Error message
PDO::errorInfo(): Array ( [0] => HY000 [1] => 1 [2] => table d0000kv_c_name has 4 columns but 2 values were supplied )
Your select SELECT 3 AS 'c_name','manash' AS 'value' UNION SELECT 2,'ram' UNION SELECT 1,'rahim' return 2 columns but your table d0000ke_c_name has 4 columns.
You have to declare the to be filled fields in your INSERT INTO:
$sql = "INSERT INTO d0000kv_c_name (c_name, value) SELECT 3 AS 'c_name','manash' AS 'value' UNION SELECT 2,'ram' UNION SELECT 1,'rahim'";
(In this case the fields sc_version and sc_state will get the default values.)
Or you should add the missing fields (e.g. "0, 0" for fields sc_version and sc_state) to your SELECT:
$sql = "INSERT INTO d0000kv_c_name SELECT 3 AS 'c_name','manash' AS 'value', 0, 0 UNION SELECT 2, 'ram', 0, 0 UNION SELECT 1,'rahim', 0, 0";

Use array as table in MySql JOIN

I would like to use data from an array to add a column and make a join on a MySql table.
Let's say, on one hand, we have an array ($relevance):
$relevance = array(
array('product_id' => 1, 'relevance' => 2),
array('product_id' => 2, 'relevance' => 5),
array('product_id' => 3, 'relevance' => 1),
);
And on the other hand, we have this table (products):
product_id | product_name
--------------------------
1 | Product 1
2 | Product 2
3 | Product 3
Now, I want to select data from the products table and joining them with $relevance based on their product_id in order to get something like this:
product_id | product_name | relevance
---------------------------------------
1 | Product 1 | 2
2 | Product 2 | 5
3 | Product 3 | 1
In other words, how can I make a SELECT with LEFT JOIN using data from both the MySql database and an array which would "mean" something like this:
SELECT `p`.*, `{{$relevance}}`.* FROM `products` AS `p`
LEFT JOIN `{{$relevance}}`
ON p.product_id = {{$relevance}}.product_id
pure sql solution, not efficient though for big recordsets:
$relevances = array()
foreach ($relevance as $v){
$relevances[] = "SELECT {$v['product_id']} as product_id, {$v['relevance']} as relevance"
}
$sql = implode(' UNION ', $relevances);
$sql = "SELECT p.product_id, p.product_name, r.relevance
FROM products p
JOIN ($sql) r ON p.product_id=r.product_id";
Well, you can make another table relevance and then you could just use JOIN. Or you can use loop to get those data. Something like
$relevance = array(
array(1, 'relevance' => 2),
array(2, 'relevance' => 5),
array(3, 'relevance' => 1),
);
$q = mysql_query("SELECT * FROM products")
while($r = mysql_fetch_assoc($q))
{
$productRelevance = $relevance[$r['prod_id']-1];
}
Hoewever this code may fail if you delete some product and those ids wouldn' be in order, e.g.: 1,2,5,6,7,10. I recommend you to use another table.

Categories