Yii2 ActiveQuery join keep returns distinct values - php

I have two tables as below
table halte :
CREATE TABLE `halte` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nama` varchar(255) NOT NULL,
`lat` float(10,6) DEFAULT NULL,
`lng` float(10,6) DEFAULT NULL,
PRIMARY KEY (`id`)
)
table stops :
CREATE TABLE `stops` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_halte` int(11) DEFAULT NULL,
`sequence` int(2) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_halte` (`id_halte`)
)
I also have some other tables which don't cause any problems.
Halte table has many to one relation to stop. The problem is when i try to get rows from halte table using right join to table stops, Yii only returns unique rows. Yii won't return same halte's row more once even stop table has more than one record related to same row in halte table.
Here's my code
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
I have tried distinct(false) but no result.
I've also check debugger and it run right query i want :
SELECT `halte`.* FROM `halte` RIGHT JOIN `stops` ON halte.id = stops.id_halte WHERE `stops`.`id_rute`='1' ORDER BY `sequence`
I tried to run that query manually and it returned 29 rows which is what what i want. But in Yii, it only returned 27 rows because 2 rows is same record in halte table.
I know i can achieve this using yii\db\Query, but i want to use ActiveRecord.
Are there any way to work around this?
I would really appreciate your opinion/help.
Thanks.

Check the sql command generated by you active query
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
echo $haltes->createCommand()->sql;
or to get the SQL with all parameters included try:
$haltes->createCommand()->getRawSql();
And compare the code generated by ActiveQuery with your created manually ..

Related

SQL - After receiving rows of the same data from a SELECT INNER JOIN with a WHERE...How do I take one time what is different / unique

I can use LIMIT to surrender myself to one row but I would like to learn how I can provide one of each rows rather than the several of the same rows / data
Goto : http://inks-etc.com/Script/SQL/loginform.php
Username: jason
Password: 123
Sounds like you have this setup:
create table `some_table` (
`uniq_id` bigint(20) unsigned not null auto_incremenet,
`some_data` varchar(200) not null,
`some_other_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
create table `some_other_table` (
`other_id` bigint(20) unsigned not null auto_incremenet,
`link_to_uniq_id` bigint(20) unsigned not null,
`multiple_entry_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
Where some_other_table can match some_table multiple times. It also sounds like you are trying something like this, and wanting one row per uniq_id:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
The way that you can modify this type of query to get only one entry per uniq_id is something like this, using the group by directive:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
group by some_table.uniq_id
Hopefully I understood your question, and hopefully this answers it.

Yii joining two table using relations in model

Hi I have these two tables that I want to join using relations in Yii, The problem is Im having a hard time figuring out how Yii relation works.
picturepost
id
title
link_stat_id
linkstat
id
link
post_count
I also have a working SQL query. This is the query I want my relation to result when I search when I want to get picturepost
SELECT picturepost.id, picturepost.title,linkstat.post_count
FROM picturepost
RIGHT JOIN linkstat
ON picturepost.link_stat_id=linkstat.link;
I want something like this when I search for a post.
$post = PicturePost::model() -> findByPk($id);
echo $post->linkCount;
Here's my table for extra info:
CREATE TABLE IF NOT EXISTS `picturepost` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` text COLLATE utf8_unicode_ci DEFAULT NULL,
`link_stat_id` char(64) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM;
CREATE TABLE IF NOT EXISTS `linkstat` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`link` char(64) COLLATE utf8_unicode_ci NOT NULL,
`post_count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `post_count` (`post_count`),
KEY `link_stat_id` (`link`)
) ENGINE=InnoDB;
Thanks in advance I hope I explained it clearly.
There are a few tutorial regarding this, and I won't repeat them, but urge you to check them out.
The easiest starting point will be to create your foreign key constraints in the database, then use the Gii tool to generate the code for the model, in this case for the table picturepost.
This should result in a class Picturepost with a method relations(),
class Picturepost extends {
public function relations()
{
return array(
'picturepost_linkstats' => array(self::HAS_MANY,
'linkstat', 'link_stat_id'),
);
}
This links the 2 tables using the *link_stat_id* field as the foreign key (to the primary key of the linked table).
When you are querying the table picturepost, you can automatically pull in the linkstat records.
// Get the picturepost entry
$picturepost = PicturePost::model()->findByPk(1);
// picturepost_linkstats is the relationship name
$linkstats_records = $picturepost->picturepost_linkstats;
public function relations()
{
return array(
'linkstat' => array(self::HAS_ONE, 'Linkstat', array('link_stat_id'=>'link')),
);
}
More on yii relations.
This assumes that you have an active record model Linkstat that represents data in table linkstat.

mysql 'likes' structure table

I'm working on a web site where users can post articles with this table structure :
CREATE TABLE IF NOT EXISTS `articles` (
`id_articles` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(10) unsigned NOT NULL,
`articles` text NOT NULL,
PRIMARY KEY (`id_articles`),
UNIQUE KEY `id_articles` (`id_articles`),
KEY `id_users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Each user can 'like' the articles.
Is that the right way below to create a 'like table' :
CREATE TABLE IF NOT EXISTS `articles_likes` (
`id_articles` int(10) unsigned NOT NULL,
`id_users` int(10) unsigned NOT NULL,
KEY `id_articles` (`id_articles`,`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It is correct but you will want to add separte indexes on id_articles and id_users (also you might want to name the columns 'id_article' and 'id_user' for sanity).
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article` (`id_article`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
The reason you want separate indexes is because in mysql if you create an index on columns (A, B) that index will be used in queries having in the where clause column A, or columns A and B.
In your case for example if you made a query "SELECT * FROM article_likes WHERE id_user=X" this query would not use an index.
An ever better option would be to add a combined index and a separate index on the second column from the combined index. Like this:
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article_user` (`id_article`, `id_user`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
This way you would have optimal performance on queries like 'WHERE id_user=X', "WHERE id_article=X', "WHERE id_article=X AND id_user=Y"
This is a valid way Chris. You can use COUNT() to match the id_articles in the articles_likes table against the current article you are viewing in articles.
$articles_id = 23;
mysql_query("SELECT COUNT(*) FROM articles_likes
WHERE id_articles = ".$articles_id);
You can also just leave COUNT() (MySQL) out and instantly know which users are the "likers" of the articles and use count() (PHP) on the returned Array to duplicate the effect of COUNT() in MySQL.
i would have a total of 3 tables. an articles table, and the user id could be a column in that for users who submit articles , but you need a separate user table since not all users will submit articles (i am assuming), and then a 3rd table for likes, that takes the primary key from users and the primary key from articles and uses them as foreign keys. so each time an article is liked, an entry is made in the 3rd table

what's wrong with this SQL statement causing column count doesn't match value count at row 1?

Mysql table (migration_terms) fields are as follows
oldterm count newterm seed
I used the following create table statment.
CREATE TABLE `migration_terms`
(
`oldterm` varchar(255) DEFAULT NULL,
`count` smallint(6) DEFAULT '0',
`newterm` varchar(255) DEFAULT NULL,
`seed` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`seed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
And It works, no problems there.
but then when I used the following insert into statement to populate it;
"INSERT INTO migration_terms
SELECT looseterm as oldterm,
COUNT(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
I get this error;
Column count doesn't match value count at row 1
I cannot figure out why?
If you need the table structure of the looseterms table, it was created by the following create table statement.
CREATE TABLE looseterms
(
`seed` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`looseterm` varchar(255)
)
You need to specify the columns if your select statement has fewer columns than the table
"INSERT INTO migration_terms
(oldterm,
count)
SELECT looseterm AS oldterm,
Count(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
From MySql docs on Insert Syntax
If you do not specify a list of column names for INSERT ... VALUES or
INSERT ... SELECT, values for every column in the table must be
provided by the VALUES list or the SELECT statement. If you do not
know the order of the columns in the table, use DESCRIBE tbl_name to
find out.
Your insert is adding 2 columns of data, whereas your table's definition has 4 columns

PHP/MySQL Search code and logic for relational database schema

I have created this database schema and with help from several users on here, I have a database which takes user submitted business entries stored in the business table, which are additionally grouped under one or several of about 10 catagories from the catagories table, in the tbl_works_catagories table by matching the bus_id to the catagory id.
For example, bus_id 21 could be associated with catagory_id 1, 2, 5, 7, 8.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL
)
Now, what i want to do next is a search function which will return businesses based on the catagory. For example, say one of the businesses entered into the business table is a bakers and when it was entered, it was catagorised under Food (catagory_id 1) and take-away (catagory_id 2).
So a visitor searches for businesses listed under the Food catagory, and is returned our friendly neighbourhood baker.
As with all PHP/MySQL, i just can't (initially anyway) get my head around the logic, never mind the code!
You should setup foreign keys in your tables to link them together.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL,
FOREIGN KEY (`bus_id`) REFERENCES business(`bus_id`),
FOREIGN KEY (`category_id`) REFERENCES categories(`category_id`)
)
Then your search query would be something like:
SELECT b.*
FROM business b, categories c, tbl_works_categories t
WHERE
b.bus_id = t.bus_id AND
c.category_id = t.category_id AND
c.category_id = *SOME SEARCH VALUE*
which using JOIN would be written as:
SELECT b.*
FROM business b
JOIN tbl_works_categories t
ON b.bus_id = t.bus_id
JOIN categories c
ON c.category_id = t.category_id
WHERE c.category_id = *SOME SEARCH VALUE*
Maybe you want something like this:
SELECT `bus_id` FROM `tbl_works_categories` WHERE `category_id` = *some id from the search*
AND `category_id` = *some other id from the search*;
Although you'd need those ids- there are a few ways to do this, I'll describe probably the most straight forward...
You get categories from $_POST, so let's just say you have 2 of them entered. (Food, and take-away). Parse these however you want, there are multiple ways, but the point is they're coming from $_POST.
execute this sort of thing for each one you find:
SELECT `category_id` FROM `categories` WHERE `category_name` LIKE '%*the name from $_POST*%';
Store these results in an array...based on how many you have there you can build an applicable query similar to the one I describe first. (Keep in mind you don't need and AND there, that's something you have to detect if you return > 1 category_id from the second query here)
I'm not going over things like security..always be careful when executing queries that contain user submitted data.
An alternate solution might involve a join, not too sure what that'd look like off the top of my head.
Good luck.
If you want all businesses that are related to the given category-id, your SQL-statement would look something like this:
SELECT `business`.`bus_name`
FROM `business`
WHERE `business`.`bus_id` = `tbl_works_categories`.`bus_id`
AND `categories`.`category_id` = `tbl_works_categories`.`category_id`
AND `categories`.`category_id` = 1;
Where 1 in this case is your food-category, but could be your PHP variable where the ID of the category the user selected is stored.
And one hint: Be sure to name your tables either in plurar or in singular. You are mixing both and could get confused.

Categories