Join two tables mysqli - sql

I have a question about my select from two tables. I have this tables:
pubstats sites
`id` int(11) NOT NULL, `id` int(11) NOT NULL,
`website_id` varchar(10) NOT NULL, `username` varchar(100) NOT NULL,
`user_id` varchar(10) NOT NULL, `url` varchar(250) NOT NULL,
`amount` float(10,4) NOT NULL, `name` varchar(50) NOT NULL,
`impressions` varchar(30) NOT NULL, `category` varchar(50) NOT NULL,
`date` date NOT NULL `date` date NOT NULL,
`status` varchar(50) NOT NULL DEFAULT 'pending'
I want to select all dates from sites and impressions and amount from pubstats and display it! I tried with another select in loop but not work and i want to use JOIN function!
Now i have this select that display dates from sites table and i want for each website to display impressions and amount:
$stmt = $mysqli->prepare("SELECT id, username, url, name, category, date, status FROM sites WHERE username = '$username' order by id DESC");
$stmt->execute();
mysqli_stmt_bind_result($stmt, $id, $username, $url, $name, $category, $date, $status);
$stmt->store_result();

Try this INNER JOIN query
SELECT a.*, b.impression, b.amount
FROM sites a
INNER JOIN pubstats b
ON a.id = b.website_id
With this query you will select all columns from table sites (alias table a) and only two columns from table pubstats (alias table b)

Related

Self-Referencing Table SQL Select last element from included elements

I have tables:
create table Branches(
Id int primary key identity,
IdSection int not null,
IdMasterBranch int null,
[Name] varchar(100) not null,
[Description] varchar(300) null
)
create table Threads(
Id int primary key identity,
IdBranch int not null,
IdUserAuthor int not null,
[Name] varchar(100) not null,
IsPinned bit not null,
IsOpen bit not null,
HasPoll bit not null
)
create table Posts(
Id int primary key identity,
IdThread int not null,
IdUserAuthor int not null,
Body varchar(4000) not null,
IsEdited bit not null,
[Index] int not null,
Created datetime2 not null,
Updated datetime2 null
)
Branches is self referencing table, that contains another branches.
And i wanna write sql request to select all master branches (IdMasterBranch IS NULL) with last thread and last post.
Something like this:
select * from Branches branch
left join BranchModerators moderator on branch.Id = moderator.IdBranch
left join Threads thread on branch.Id = thread.IdBranch
left join (select * from (
select *,
ROW_NUMBER() over (
partition by IdThread
order by [Index] desc
) as RowNumber
from Posts
) groups
where groups.RowNumber = 1) lastPost on thread.Id = lastPost.IdThread
But i wanna take last thread and post with included inner branches too.
What is the best solution for it?

SQL Outer Join -- Join requires 3 tables

I'm using SQL Server query designer to try and form an outer query that will return the full name and address of each insured with home policies and those without policies. My create statements are the following:
CREATE TABLE Address (
AddressID integer NOT NULL,
HouseNumber Integer NOT NULL,
Street varchar(20) NOT NULL,
CityCounty varchar(20) NOT NULL,
StateAbb char(2),
CountryAbb char(2) NOT NULL,
Zip char(5) NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Address PRIMARY KEY (AddressID));
CREATE TABLE Insured(
InsuredID integer NOT NULL,
FirstName varchar(15) NOT NULL,
LastName varchar(15) NOT NULL,
MI char(1),
DateOfBirth date NOT NULL,
CreditScore integer NOT NULL,
AddressID integer NOT NULL,
DriversLicenseNumber varchar(35),
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Insured PRIMARY KEY (InsuredID),
CONSTRAINT FK_InsuredAddress FOREIGN KEY (AddressID) references Address);
CREATE TABLE Policy(
PolicyID integer NOT NULL,
EffectiveDate date NOT NULL,
TerminationDate date NOT NULL,
Amount Numeric (8,2) NOT NULL,
PolicyYear integer NOT NULL,
PolicyType char(1) NOT NULL,
InsuredID integer NOT NULL,
AddressID integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Policy PRIMARY KEY (PolicyID),
CONSTRAINT FK_PolicyAddress FOREIGN KEY (AddressID) references Address,
CONSTRAINT FK_PolicyInsured FOREIGN KEY (InsuredID) references Insured);
CREATE TABLE Home(
PolicyID integer NOT NULL,
ExteriorType varchar(30) NOT NULL,
Alarm char(3) NOT NULL,
DistanceToFireStation integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Home PRIMARY KEY (PolicyID),
CONSTRAINT FK_HomePolicy FOREIGN KEY (PolicyID) references Policy);
CREATE TABLE Auto(
PolicyID integer NOT NULL,
VinNumber varchar(30) NOT NULL,
Make varchar(15) NOT NULL,
Model varchar(20) NOT NULL,
MilesPerYear integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Auto PRIMARY KEY (PolicyID),
CONSTRAINT FK_AutoPolicy FOREIGN KEY (PolicyID) references Policy);
I believe that the query requires tables address, insured, policy and an outer right or left join but I cant get SQL server to recognize this as it keeps forming an inner join and cross join. What do I need for a query that returns insureds with home policies and their addresses and insureds with no policy and their addresses?
What I've tried so far:
SELECT Insured.InsuredID, Insured.FirstName,
Insured.LastName, Address.HouseNumber,
Policy.PolicyID
FROM Address RIGHT JOIN Policy
ON Address.AddressID = Policy.AddressID
RIGHT JOIN Insured ON Policy.AddressID = Insured.AddressID
ORDER BY Insured.InsuredID
This is the most recent query that returns what I need for insureds with a home policy but for the insureds without a policy I get nulls in the address.
SELECT i.InsuredID, i.FirstName, i.MI, i.LastName,
a.HouseNumber, a.Street, a.CityCounty, a.StateAbb, a.CountryAbb, a.Zip
FROM INSURED i
LEFT JOIN (SELECT * FROM Policy WHERE PolicyType = 'H') HomePolicy on
i.InsuredID = HomePolicy.InsuredID
LEFT JOIN Address a on HomePolicy.AddressID = a.AddressID;
Could you try this query:
SELECT i.InsuredID,
i.FirstName,
i.LastName,
a.HouseNumber,
p.PolicyID
FROM insured i
LEFT JOIN policy p ON i.AddressID = p.AddressID AND p.PolicyType = 'H'
LEFT JOIN address a ON i.AddressID = a.AddressID
ORDER BY i.InsuredID;
I think the joins were in the wrong order. Does this give you what you need?
Update: Joining the Insured table to the Address table will show you addresses regardless of if they have a policy or not.
Database design seem good.I think we have minor doubts regarding "PolicyType" column. what value it hold and what is the purpose of this column.
Say PolicyType='H' it mean that it is home policy . Or other way of finding same query is to check if that policyid exists in home table.
Is this correct ?
Main query,
What do I need for a query that returns insureds with home policies
and their addresses and insureds with no policy and their addresses?
Check this script,
--insureds with home policies and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
A.HouseNumber
,1 INDICATE
from Insured i
INNER JOIN policy p ON i.InsuredID = p.InsuredID
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT PolicyID FROM Home H WHERE h.PolicyID=P.PolicyID)
AND NOT EXISTS(SELECT PolicyID FROM [Auto] a WHERE A.PolicyID=P.PolicyID)
UNION ALL
--insureds with no policy and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
,A.HouseNumber
,0 INDICATE
from Insured i
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT InsuredID FROM policy p WHERE i.InsuredID = p.InsuredID )
I have use "EXISTS clause" because that table column is not require in your output.

Counting forum topics and replies

I have 2 tables: posts and forum_topics. Each post (a reply) is associated with another post (a forum topic, which is then associated with the forum_topics tables).
Problem: I need to count all forum topics and replies in the posts table. This is what I have so far:
SELECT ForumTopic.id, ForumTopic.title, ForumTopic.modified, COUNT(ReplyLeftOuterJoin.id) as replies_count
FROM forum_topics AS ForumTopic
LEFT OUTER JOIN posts AS PostLeftOuterJoin
ON PostLeftOuterJoin.object_id = ForumTopic.id
AND PostLeftOuterJoin.object_type = 'forum_topic'
AND PostLeftOuterJoin.status = 'approved'
LEFT OUTER JOIN posts AS ReplyLeftOuterJoin
ON ReplyLeftOuterJoin.object_id = PostLeftOuterJoin.id
AND ReplyLeftOuterJoin.object_type = 'post'
AND ReplyLeftOuterJoin.status = 'approved'
WHERE ForumTopic.forum_category_id = 'some_id'
Edit
Currently I'm only getting a count of all replies associated with a forum_topic (post) in the posts table. I would like to get a count of forum_topics in posts table associated with a forum topic in the forum_topics table.
NB FYI, a solution to this problem should use one query only.
Here is the schema of the two tables:
DROP TABLE IF EXISTS `posts`;
CREATE TABLE `posts` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`context_id` bigint(20) unsigned DEFAULT NULL,
`context_type` enum('resource','module','kwik','user','assignment') COLLATE utf8_unicode_ci DEFAULT NULL,
`is_private` tinyint(1) NOT NULL,
`is_unread` tinyint(4) NOT NULL,
`last_replied` datetime NOT NULL,
`object_id` bigint(20) unsigned DEFAULT NULL,
`object_type` enum('forum_topic','forum','user','post') COLLATE utf8_unicode_ci DEFAULT NULL,
`status` enum('approved','unapproved','disabled') COLLATE utf8_unicode_ci NOT NULL,
`post` text COLLATE utf8_unicode_ci NOT NULL,
`user_id` bigint(20) unsigned NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP TABLE IF EXISTS `forum_topics`;
CREATE TABLE `forum_topics` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`view_count` int(10) unsigned NOT NULL,
`forum_category_id` bigint(20) unsigned NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SELECT
ForumTopic.forum_category_id,
COUNT(DISTINCT PostLeftOuterJoin.id) as forumtopics_count,
COUNT(ReplyLeftOuterJoin.id) as replies_count
FROM forum_topics AS ForumTopic
LEFT OUTER JOIN posts AS PostLeftOuterJoin
ON PostLeftOuterJoin.object_id = ForumTopic.id
AND PostLeftOuterJoin.object_type = 'forum_topic'
AND PostLeftOuterJoin.status = 'approved'
LEFT OUTER JOIN posts AS ReplyLeftOuterJoin
ON ReplyLeftOuterJoin.object_id = PostLeftOuterJoin.id
AND ReplyLeftOuterJoin.object_type = 'post'
AND ReplyLeftOuterJoin.status = 'approved'
WHERE ForumTopic.forum_category_id = 'some_id'
GROUP BY
ForumTopic.forum_category_id
;
maybe you can get the result in two queries
the following query will give you the count of posts in each forum
select f.id,f.title,f.modified,Type='Posts',Number=count(*)
from forum_topics as f
inner join posts p on p.forumid=f.id --u used in your query PostLeftOuterJoin.id ( is this the forum id or the posts id ?)
where p.status='approved' and p.object_type='forum_topic'
group by f.id,f.title,f.modified
union
select f.id,f.title,f.modified,Type='Replies',Number=count(*)
from forum_topics as f
inner join posts p on p.forumid=f.id --u used in your query PostLeftOuterJoin.id ( is this the forum id or the posts id ?)
where p.status='approved' and p.object_type='posts'
group by f.id,f.title,f.modified
to distinguish between the posts and replies, i added the Type
and from your application level you can get the forum post count when Type=Posts and same as for the replies
another method
select f.id,f.title,f.modified,Posts=(select count(*) from posts p where f.id=p.object_id and p.status='approved' and p.object_type='forum_topic'),
Replies=(select count(*) from posts p on where f.id=p.object_id
and p.status='approved' and p.object_type='posts')
from forum_topics f
where f.forum_category_id='someid'
hope that this will help you
regards

sql query is returning the same values twice

I have this sql query, and it should be returning two values, which is does but it returns each returned row twice, the sql looks like this,
SELECT * FROM `mailers`
LEFT JOIN `mailer_content` ON `mailers`.`id` = `mailer_content`.`mailer_id`
LEFT JOIN `mailer_images` ON `mailer_content`.`id` = `mailer_images`.`content_id`
WHERE `mailers`.`id` = 26
The table structure for the tables I am query look like this,
-- --------------------------------------------------------
--
-- Table structure for table `mailers`
--
CREATE TABLE `mailers` (
`id` int(11) NOT NULL auto_increment,
`mailer_title` varchar(150) NOT NULL,
`mailer_header` varchar(60) NOT NULL,
`mailer_type` enum('single','multi') NOT NULL,
`introduction` varchar(80) NOT NULL,
`status` enum('live','dead','draft') NOT NULL,
`flag` enum('sent','unsent') NOT NULL,
`date_mailer_created` int(11) NOT NULL,
`date_mailer_updated` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=29 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_content`
--
CREATE TABLE `mailer_content` (
`id` int(11) NOT NULL auto_increment,
`headline` varchar(320) NOT NULL,
`content` text NOT NULL,
`mailer_id` int(11) NOT NULL,
`position` enum('left','right','centre') default NULL,
`tab_1_name` varchar(25) default NULL,
`tab_1_link` varchar(250) default NULL,
`tab_2_name` varchar(25) default NULL,
`tab_2_link` varchar(250) default NULL,
`tab_3_name` varchar(25) default NULL,
`tab_3_link` varchar(250) default NULL,
`tab_4_name` varchar(25) default NULL,
`tab_4_link` varchar(250) default NULL,
`created_at` int(10) NOT NULL,
`updated_at` int(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `mailer_id` (`mailer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_images`
--
CREATE TABLE `mailer_images` (
`id` int(11) NOT NULL auto_increment,
`title` varchar(150) NOT NULL,
`filename` varchar(150) NOT NULL,
`mailer_id` int(11) NOT NULL,
`content_id` int(11) default NULL,
`date_created` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=49 ;
I am sure that is must be a problem with my sql I just do not know what the problem is
If you use SELECT DISTINCT SQL will not return dupplicated rows, if there are some.
SELECT DISTINCT * FROM `mailers` LEFT JOIN `mailer_content` ON `mailers`.`id` = `mailer_content`.`mailer_id` LEFT JOIN `mailer_images` ON `mailer_content`.`id` = `mailer_images`.`content_id` WHERE `mailers`.`id` = 26
U can use group by smthng. It will delete the same records.
but u can delete nonsame rows. Use smthng without same values in different rows in original table.
try this
SELECT * FROM mailers
LEFT JOIN mailer_content ON mailers.id = mailer_content.mailer_id
LEFT JOIN mailer_images ON mailer_content.id = mailer_images.content_id
WHERE mailers.id = 26 GROUP BY mailers.id
It doesn't look like an SQL isse to me; I suspect this is more likely down to the data in your tables.
My guess is that there are two rows in mailer_content where mailers.id = 26 and then two rows (or possibly 1 and 3) in mailer_images for each of the mailer_contents.
How many rows do each of the following queries return?
SELECT * FROM `mailers`
WHERE `mailers`.`id` = 26
SELECT * FROM `mailer_content`
WHERE `mailer_content`.`id` = 26
My guess is that the first returns 1 row (because it has a primary key on id) and that the second returns two rows.
That all may be fine but my guess is that the following query returns 4 records:
SELECT * FROM `mailer_content`
LEFT JOIN `mailer_images` ON `mailer_content`.`id` = `mailer_images`.`content_id`
WHERE `mailer_content`.`id` = 26
Because either each content has two images each OR one content has one image and the other has three.

SQL joins query not acting as wanted

I have the following tables:
CREATE TABLE `attendance_event_attendance` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`talk_id` varchar(200) NOT NULL,
`membersAttended_id` varchar(200) NOT NULL,
PRIMARY KEY (`id`),
KEY `attendance_event_attendance_9ace4e5a` (`talk_id`),
KEY `attendance_event_attendance_3c0dadb7` (`membersAttended_id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
CREATE TABLE `attendance_member` (
`name` varchar(200) NOT NULL,
`telephone_number` varchar(200) NOT NULL,
`email_address` varchar(200) NOT NULL,
`membership_type` varchar(1) NOT NULL,
`membership_number` varchar(200) NOT NULL,
PRIMARY KEY (`membership_number`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `attendance_talk` (
`title` varchar(200) NOT NULL,
`speaker` varchar(200) NOT NULL,
`date_of_talk` date NOT NULL,
PRIMARY KEY (`title`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
I want to select all the members that have not attended the two latest talks. The query I have written looks like this:
SELECT m.name
from attendance_member as m
left outer join attendance_event_attendance as ea on (ea.membersAttended_id=m.membership_number)
join attendance_talk as t on (ea.talk_id = t.title)
where t.date_of_talk >= 2010-06-01
AND ea.membersAttended_id = null;
Is this correct? Or have I not understood joins correctly?
A somewhat horrible approach, I fear - but one that should work...
SELECT m.name
from attendance_member as m
left outer join (
SELECT ea.membersAttended_id
FROM attendance_event_attendance as ea
join attendance_talk as t on (ea.talk_id = t.title)
where t.date_of_talk >= 2010-06-01
GROUP BY ea.membersAttended_id
HAVING COUNT(*) = 2
) attendingmembers
ON attendingmembers.membersAttended_id = m.membership_number
WHERE attendingmembers.membersAttended_id IS NULL
Pretty much exactly like you would say it in English
Select Distinct m.name -- Select names
From attendance_member M -- of members
Where Not Exists -- who did not attend the last two talks
(Select * From attendance_event_attendance a
Join attendance_talk t
On a.talk_id = t.title
Where a.membersAttended_id = m.membership_number
And (Select Count(*) From attendance_talk
Where date_of_talk >= t. date_of_talk) <= 2)
NOTE: The subquery:
(Select * From attendance_event_attendance a
Join attendance_talk t
On a.talk_id = t.title
Where a.membersAttended_id = m.membership_number -- (correlated w/outer query)
And (Select Count(*) From attendance_talk
Where date_of_talk >= t. date_of_talk) <= 2)
returns the list of members who attended the talks which have 2 or fewer subsequent talks