SELECT statements have different number of columns - php

I am making a small php website in which you can follow others and then see their post.
I have three tables-
1.Posts, which has post_id and author_id
2.follow, which has following and follower
3.users, which has id, username, and all other stuff. I try the following in sql-
SELECT * FROM posts,follow,users WHERE posts.author_id=users.id AND users.id=follow.following AND follow.follower='$id' UNION SELECT * FROM posts,users WHERE posts.author_id=users.id AND users.id='$id'
Where $id is the id of the user logged in.
It displays the following error-
#1222 - The used SELECT statements have a different number of columns
I have searched for hours but I cannot find the answers to match with my query.
I will really appreciate an answer with a better version of the above code.
Thanks in advance.

Perhaps a JOIN would serve you better ... something like this:
SELECT * FROM posts
JOIN users on posts.author_id=users.id
JOIN followers on users.id=follow.following
WHERE follow.follower='$id'

When you union two queries together, the columns on both must match.
You select from posts,follow,users on the first query and posts,users on the second.
this won't work.
From the mysql manual:
The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type

Related

Query selected columns from two tables with a Condition clause

I have two tables-
1) ****Company_Form****
[Contract_No#,Software_Name,Company_Name,Vendor_Code]
2) ****User_Form****
[Contract_No,Invoice_No#,Invoice_Date,Invoice_Amount,Invoice_Submit_Date]
Fields denoted with # and bold are primary keys.
=>The user has to enter a software name for which he wants to get the data of.
=>I have to structure a query in which I have to display the result in the following form:
[Contract#,Software_Name,Company_Name,Invoice_No,Invoice_Date,Invoice_Submission_Date]
Now,
one Contract_No can contain many Invoice_no under its name in
the User Form table.
One Contract_No can occur one time only in
Company_Form table
The retrieved records have to be group by the latest Invoice_Date
I came to the logic that:
I have to first retrieve all the contract numbers with that software
name from Company_Form table.
I have to query that contract number from User_Form table and display
the data for each matched contract no. fetched from Company_Form
table.
The problem is that I am unable to structure a query in SQL that can do the task for me.
Kindly help me in formulating the query.
[PS] I am using SQL with PHP.
I tried a query like:
I tried one approach as :
SELECT a.ContractNo,a.SoftwareName,a.CompanyName,b.InvoiceNo,b.InvoiceDate,b.InvAmount,b.InvoiceSubmitDate
FROM Company_Form as a,User_Form as b
WHERE b.ContractNo IN(SELECT ContractNo FROM Company_Form WHERE
SoftwareName='$Sname') AND a.ContractNo=b.ContractNo;
But I am getting a error that sub query returns more than 1 row.
Can I get help from this?
I am assuming you are attempting to find the most recent price of the user selected software and its corresponding invoice. Here is an approach to do this. If this is tested to your satisfaction, I can add necessary explanation.
select uf.Contract_No#,
cf.Software_Name,
cf.Company_Name,
uf.Invoice_No#,
uf.Invoice_Date,
uf.Invoice_Amount,
uf.Invoice_Submit_Date
from User_Form uf
inner join (
-- Most recent sale of software
select Contract_No#, max(Invoice_Date)
from User_Form
group by Contract_No#
) latest
on (
-- Filter via join for latest match records
uf.Contract_No# = latest.Contract_No#
and uf.Invoice_Date = latest.Invoice_Date
)
inner join Company_Form cf
on cf.Contract_No# = uf.Contract_No#
where cf.Software_name = :software_name
If the requirement allows your sub query to return more than one row, I would suggest you to use IN instead of = in the where clause of your main query.
Please note that I have just looked at the query and have not fully understood the requirements.
Thanks.
I worked around for some time and finally came to the following query which works like a charm
SELECT a.ContractNo,a.SoftwareName,a.CompanyName,b.InvoiceNo,b.InvoiceDate,b.InvAmount,b.ISD
FROM Company_Form as a,User_Form as b
WHERE b.ContractNo IN (SELECT ContractNo FROM Company_Form WHERE SoftwareName='$Sname')
AND a.ContractNo=b.ContractNo;
If anybody needs help in understanding the logic of this query,feel free to comment below.

MYSQL/PHP - Select all columns from table records distincting by one column

I'm a bit confused about DISTINCT keyword. Let's guess that this query will get all the records distincting the columns set in the query:
$query = "SELECT DISTINCT name FROM people";
Now, that query is fetching all the records distincting column "name" and at the same time only fetching "name" column. How I'm supposed to ONLY distinct one column and at the same time get all the desired columns?
This would be the scheme:
NEEDED COLUMNS
name
surname
age
DISTINCTING COLUMNS
name
What would be the correct sintaxis for that query? Thanks in advance.
If you want one row per name, then a normal method is an aggregation query:
select name, max(surname) as surname, max(age) as age
from t
group by name;
MySQL supports an extension of the group by, which allows you to write a query such as:
select t.*
from t
group by name;
I strongly recommend that you do not use this. It is non-standard and the values come from indeterminate matching rows. There is not even a guarantee that they come from the same row (although they typically do in practice).
Often, you want something like that biggest age. If so, you handle this differently:
select t.*
from t
where t.age = (select max(t2.age) from t t2 where t2.name = t.name);
Note: This doesn't use group by. And, it will return duplicates if there are multiple rows with the same age.
Another method uses variables -- another MySQL-specific feature. But, if you are still learning about select, you should probably wait to learn about variables.

SQL Join can't figure it out

I have a table called website that contains some data about websites. The columns of this table are: id, website, quick_url, user_id, status, etc.
Each website that is in the table was added by a user, which is is saved in the user_id column.
I have another table called blocks that has only 3 columns: id, user_id, website_id.
I want to get all the websites from the website table, that were not added by a given user_id, but also, only the websites that were not blocked by the given user_id. So, websites that were not added by a given user or blocked by him.
Here is what I've tried:
SELECT * FROM website LEFT OUTER JOIN blocks ON tbl_website.userid = blocks.user_id WHERE website.user_id = blocks.user_id AND blocks.user_id = NULL AND website,user_id != '177' LIMIT 500;
It doesn't give me the wanted results ...
First, I've tried to do it like this:
SELECT * FROM tbl_website WHERE id<>(SELECT website_id from tbl_website_blocks WHERE user_id = '177')
which makes much more sense for me than my previous query, but I get this error: Subquery returns more than 1 row
I guess you can't have a "loop in loop" in an SQL query.
I'm aware that I could do two queries, and filter the results, but I would like to do it as much as possible from the SQL language, so that I don't "overload" the server.
Any suggestions would be appreciated.
In your second query rewrite the condition on
WHERE id not in (SELECT website_id from.....)
with <> you can compare it with just one value but your select returns list of values, so you can use not in to get results that are different then the selected list of IDs
Instead of '<>', try 'Not In'
SELECT * FROM tbl_website
WHERE id Not In (SELECT website_id from tbl_website_blocks WHERE user_id = '177')
I should also add this query is not a Join.

How to select all posts from database?

In database in table user I have three columns:
id
name
friends
In column friends are names of people who are friends with person whose name is stored in column name. Column friends looks like this:
friendname1,friendname2,friendname3,friendname4
Each of those friends have it's own row where name is equal to their name.
I also have another table called post where I have four columns:
id
name_posted
post
visible
What I would like now, is to select all posts from table post where name_posted is equal to name of the logged in user or any of his friends which are stored in column friends in table user.
Name of the logged in user is stored in variable $user.
For selecting only posts from logged in user I can use this:
$all_posts = mysqli_query($connect_db, "SELECT * FROM post WHERE name_posted='$user' AND visible='yes'");
but I don't know how to include to select also posts from his friends. Something like Facebook have, when you log in and you see your posts plus your friends posts. I don't know how they created that. Sorry for long post, I just wanted to give you detailed description.
For selecting data based on information across multiple tables I suggest reading up on MySQL Joins.
Maybe with two querys, first select friends something like this:
SELECT * FROM user WHERE name='$user'
You then have all his friends in string like this if I understood correctly :
friend1,friend2,friend3...
Explode $row['friends'] -> explode(',',$row['friends']); to get all friends names in array and then you can do another select in foreach loop to get all posts from friends and display it the way you like or you can even better do IN in query
select * from posts where name_posted IN ($row['friends'])
this is the other way, which would be longer
foreach($friendarray as $k=>$friend){
...
mysqli_query($connect_db,
"SELECT * from post where name_posted='$friend' AND visible='yes'");
...
}
and also the query you already have to get own posts. Don't forget to escape all values and stuff...
You could also join two tables but I cant write that query from my mind , would have to sit down and try it with real data but that would be ultimate solution for you.
Don't know if I hit it right but shout if you need help
You can do it in a single query with something like:
SELECT p.*
FROM user u
join post p
on (u.name = p.name or concat(',',u.friends,',') like concat('%,',p.name,',%')
AND p.visible='yes'
WHERE u.name='$user'
- but the performance is likely to be much poorer than if you had a properly normalised design for the relationship between users and their friends.
You should probably reconsider the design of your DB. From what you've described, you should have three tables: userinfo, friendship, posts.
That way, you can then do a quick union between all three tables to get what you're looking for in one query.
Let me talk about how I will solve that case if its required from me.
I will use the following tables
users - user_id, name, email and whatever I need
relations - relation_id, user_id, fiend_id -- this table will relate one user to other
posts - post_id, user_id, content, visible
Now basically we have everything needed.
For selecting all data from the currently logged user and all of his friend I will use the following query:
SELECT * FROM posts
WHERE Visible = 1
AND (
user_id IN (SELECT friend_id FROM relations WHERE user_id = 1)
OR
user_id = 1)
What I do here, I use nested queries to accomplish that.
The interesting part here is the nested query - which basically return "array" with the ids of my friends. MySQL IN function check the user_id against that "array" After that in the main parentheses I add OR user_id = 1 which is the my user_id.
In that way I should have the content which I want to use to my feed.
However this code I away from fast and optimized but it's good example how to do that.

SELECT COUNT(DISTINCT name), id, adress from users

With PHP I'm trying to run a SQL query and select normal columns as well as COUNT.
$sql_str = "select COUNT(DISTINCT name), id, adress from users";
$src = mysql_query($sql_str);
while( $dsatz = mysql_fetch_assoc($src) ){
echo $dsatz['name'] . "<br>";
}
The problem is that when I have "COUNT(DISTINCT name)," in my query, it will only return the first entry. When I remove it, it will return all matching entries from the db.
I could separate it and do 2 queries, but I'm trying to avoid this due to performance concerns.
What do I make wrong?
thx, Mexx
The ability to mix normal columns and aggregate functions is a (mis)feature of MySQL.
You can even read why it's so dangerous on MySQL's documentation:
https://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html
But if you really want to mix normal rows and a summary in a single query, you can always use the UNION statement:
SELECT COUNT(DISTINCT name), null, null FROM users GROUP BY name --summary row
UNION
SELECT name, id, address FROM users --normal rows
COUNT() is an aggregate function, it aggregates against the results of the rest of your query. If you want to count all distinct names, and not just the distinct names associated with the id and address that you are selecting, then yes, you will have to run two queries. That's just how SQL works.
Note that you should also have a group by clause when aggregating. I think the fact that MySQL doesn't require it is horrible, and it encourages really bad habits.
From what I understand, you want to get :
one line per user, to get each name/id/address
one line for several users at the same time, to get the number of users who have the same name.
This is not quite possible, I'd say.
A solution would be, like you said, two queries...
... Or, in your case, you could do the count on the PHP side, I suppose.
ie, not count in the query, but use an additionnal loop in your PHP code.
When you have a count() as part of the field list you should group the rest of the fields. In your case that would be
select count(distinct name), id, adress from users group by id, adress
select count(distinct name), id, adress
from users
group by id, adress
I'm assuming you want to get all your users and the total count in the same query.
Try
select name, id, address, count(id) as total_number
from users
group by name, id, address;

Categories