Mysql join acting weird - mysql

I have a very simple query but I am a beginner at this and I couldn't understand really what the problem is as it's not working properly in second case:
SELECT a.user_name, a.password, a.id, r.role_name
FROM accounts as a
JOIN roles as r ON a.role=r.id
SELECT accounts.user_name, accounts.password, accounts.id, roles.role_name
FROM accounts
JOIN roles ON accounts.role=roles.id
SELECT *
FROM accounts as a
JOIN roles as r ON a.role=r.id
accounts.role and roles.id linked with foreign key. I try to select everything using * in the third query but it didn't even get anything from second table only got everything from first table(as in the last photo). So what might be the problem ?

This behaviour has no sense, all fields must to appear when you use *
Let's do a test on SQL Fiddle
MySQL 5.6 Schema Setup:
create table t1 ( i int, a char);
insert into t1 values (1,'a');
create table t2 ( i int, b char);
insert into t2 values (1,'a');
Query 1:
select *
from t1 inner join t2 on t1.i = t2.i
Results:
| i | a | i | b |
|---|---|---|---|
| 1 | a | 1 | a |
Query 2:
select *
from t1 x inner join t2 y on x.i = y.i
Results:
| i | a | i | b |
|---|---|---|---|
| 1 | a | 1 | a |
You can see all times all fields appear. May be is a issue with the program you use to connect and make the queries. Check for twice you are executing all the sentence, not only the firsts 2 lines, also check if they are a scroll bar to see more data.

I've restarted the database with given codes:
$mysqli->query('
CREATE TABLE `crm`.`roles`
(
`id` TINYINT(1) NOT NULL AUTO_INCREMENT,
`role_name` VARCHAR(20) NOT NULL,
`edit` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
);') or die($mysqli->error);
$mysqli->query('
CREATE TABLE `crm`.`accounts`
(
`id` INT NOT NULL AUTO_INCREMENT,
`role` TINYINT(1) NOT NULL DEFAULT 1,
`user_name` VARCHAR(20) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`email` VARCHAR(100) NOT NULL,
`first_name` VARCHAR(50) NOT NULL,
`last_name` VARCHAR(50) NOT NULL,
`hash` VARCHAR(32) NOT NULL,
`active` BOOL NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (`role`) REFERENCES roles(`id`)
);') or die($mysqli->error);
and every combination of SELECT is working fine now. I don't know what the problem was since I don't remember making any changes on the tables.

Related

MySQL; get all cards & all decks associated for each cards in one request

I want to be able to see each decks where a card is and display it as following.
A card can be in multiple decks. And there will be many cards/decks.
The server is in php.
|List of cards| In decks |
|-------------|-------------------|
|CardA |DeckA, DeckC |
|CardB |DeckC, DeckF, DeckY|
|CardC | |
The database as is:
CREATE TABLE `card` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` varchar(100) NOT NULL
);
CREATE TABLE `deck` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` varchar(100) NOT NULL
);
CREATE TABLE `deck_card` (
`deck_id` INT NOT NULL ,
`card_id` INT NOT NULL ,
PRIMARY KEY (deck_id, card_id),
FOREIGN KEY (card_id) REFERENCES card(id),
FOREIGN KEY (deck_id) REFERENCES deck(id)
);
I want to avoid having to do a request for each card.
Is there a way to request all the cards and each associated deck in one request using MySQL?
The next simple query can solve your problem:
SELECT
`c`.`name` `card_name`,
COALESCE(GROUP_CONCAT(`d`.`name`),'') `deck_names`
FROM `card` `c`
LEFT JOIN `deck_card` `dc` ON `c`.`id` = `dc`.`card_id`
LEFT JOIN `deck` `d` ON `d`.`id` = `dc`.`deck_id`
GROUP BY `c`.`name`
;
Result from SQLize.online
+===========+=============+
| card_name | deck_names |
+===========+=============+
| CardA | DeckA,DeckB |
+-----------+-------------+
| CardB | DeckC,DeckE |
+-----------+-------------+
| CardC | |
+-----------+-------------+

Display unmatched data along with aggregate functions and multiple joins

So, what i have is a system using MySQL for storage that should be storing donations made by people (donators). Donation is entered into system by authorized user.
Here are create tables for all 4 tables:
CREATE TABLE `donator` (
`DONATOR_ID` int(11) NOT NULL AUTO_INCREMENT,
`DONATOR_NAME` varchar(50) NOT NULL,
`STATUS` char(1) COLLATE NOT NULL DEFAULT 'A',
PRIMARY KEY (`DONATOR_ID`)
)
CREATE TABLE `user` (
`USER_ID` int(11) NOT NULL AUTO_INCREMENT,
`USERNAME` varchar(100) NOT NULL,
`PASSWORD` varchar(200) NOT NULL,
`TYPE` char(1) COLLATE NOT NULL,
PRIMARY KEY (`USER_ID`)
)
CREATE TABLE `sif_res` (
`RES_ID` int(11) NOT NULL AUTO_INCREMENT,
`RES_NAME` varchar(50) NOT NULL,
`MON_VAL` double NOT NULL,
PRIMARY KEY (`RES_ID`)
)
CREATE TABLE `donations` (
`DONATION_ID` int(11) NOT NULL AUTO_INCREMENT,
`RESOURCE` int(11) NOT NULL,
`AMOUNT` int(11) NOT NULL,
`DONATOR` int(11) NOT NULL,
`ENTRY_DATE` datetime NOT NULL,
`ENTERED_BY_USER` int(11) NOT NULL,
PRIMARY KEY (`DONATION_ID``),
KEY `fk_resurs` (`RESOURCE``),
KEY `fk_donator` (`DONATOR``),
KEY `fk_user` (`ENTERED_BY_USER``),
CONSTRAINT `fk_1` FOREIGN KEY (`DONATOR`) REFERENCES `donator` (`DONATOR_ID`) ON UPDATE CASCADE,
CONSTRAINT `fk_2` FOREIGN KEY (`RESOURCE`) REFERENCES `sif_res` (`RES_ID`) ON UPDATE CASCADE,
CONSTRAINT `fk_3` FOREIGN KEY (`ENTERED_BY_USER`) REFERENCES `user` (`USER_ID`) ON UPDATE CASCADE
)
As you can see, I have a list of donators, users and resources that can be donated.
Now, I want to display all donators' name and their id's, however in third column I would like to display their balance (sum of all of items they donated) - this is calculated with
donation.AMOUNT * sif_res.MON_VAL
for each donation
The SQL SELECT I have written works, however donators that haven't donated anything are left out (they are not matched by JOIN). I would need that it displays everyone (with STATUS!=D) even if they don't have any entries (in that case their balance may be 0 or NULL)
This is my SQL i have written:
SELECT DONATOR_ID
, DONATOR_NAME
, round(SUM(d.AMOUNT * sr.MON_VAL)) as BALANCE
from donator c
join donations d on c.DONATOR_ID=d.DONATOR
join sif_res sr on sr.RES_ID=d.RESOURCE
where c.STATUS!='D'
group by DONATOR_ID, DONATOR_NAME
So, if i execute next sentences:
INSERT INTO donator(DONATOR_NAME, STATUS) VALUES("John", 'A'); //asigns id=1
INSERT INTO donator(DONATOR_NAME, STATUS) VALUES("Willie", 'A'); //asigns id=2
INSERT INTO user (USERNAME, PASSWORD, TYPE) VALUES("user", "pass", 'A'); //asigns id=1
INSERT INTO sif_res(RES_NAME, MON_VAL) VALUES("Flour", "0.5"); //asigns id=1
INSERT INTO donations(RESOURCE, AMOUNT, DONATOR, ENTRY_DATE, ENTERED_BY_USER) VALUES(1, 100, 1, '2.2.2017', 1);
I will get output (with my SELECT sentence above):
DONATOR_ID | DONATOR_NAME | BALANCE
--------------------------------------------
1 | John | 50
What i want to get is:
DONATOR_ID | DONATOR_NAME | BALANCE
--------------------------------------------
1 | John | 50
2 | Willie | 0
I have tried all version of joins (left, right, outer, full,..) however none of them worked for me (probably because i was using them wrong)
If it was just the problem of unmatched data i would be able to solve it, however the aggregate function SUM and another JOIN make it all more complicated
Using a left outer join on the second two tables should do the trick:
SELECT c.DONATOR_ID
, c.DONATOR_NAME
, ifnull(round(SUM(d.AMOUNT * sr.MON_VAL)),0) as BALANCE
from donator c
left outer join donations d on c.DONATOR_ID=d.DONATOR
left outer join sif_res sr on sr.RES_ID=d.RESOURCE
where c.STATUS!='D'
group by DONATOR_ID, DONATOR_NAME
I also wrapped the BALANCE expression in ifnull to display 0 instead of null.

Mysql Multiple Left Join And Sum not Working Correctly

I am new at joins.
I want to get sum of debts and incomes on mysql. But I am facing with a problem.
The problem is sum works more than normal.
Here is query
Select uyeler.*,
sum(uye_gider.tutar) as gider,
sum(gelir.tutar) as gelir
from uyeler
LEFT JOIN gelir on gelir.uye=uyeler.id
LEFT JOIN uye_gider on uye_gider.uye=uyeler.id
group by uyeler.id
First:
If I dont write group by it gives me only first row.
Does this work like this?
Main problem:
I have :
-2 row 'uye'(user)
-3 row 'gelir'(income)
-1 row 'uye_gider'(debt) value is 25
But when I execute this query the value of gider is 75.
I think its sum('uye_gider.tutar') is working 3 times because of 'gelir.tutar'
What am I doing wrong?
------Tables------
CREATE TABLE IF NOT EXISTS `gelir` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tarih` date NOT NULL,
`uye` int(11) NOT NULL,
`tutar` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `uyeler` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ad` varchar(15) NOT NULL,
`soyad` varchar(15) NOT NULL,
`tc` varchar(11) NOT NULL,
`dogum` date NOT NULL,
`cep` int(11) NOT NULL,
`eposta` varchar(50) NOT NULL,
`is` int(11) NOT NULL,
`daire` int(11) NOT NULL,
`kan` varchar(5) NOT NULL,
`web` varchar(12) NOT NULL,
`webpw` varchar(100) NOT NULL,
`tur` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `uye_gider` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uye` int(11) NOT NULL,
`tutar` float NOT NULL,
`gider` int(11) NOT NULL,
`aciklama` text COLLATE utf8_bin,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;
---End Tables---
first
Group by, groups sets of data according to the field you've picked. If you want a total sum of an entire table you should only want one row and it should not be grouped by anything. If you want to group your sums by a value, ie. the 'animals' table
| id | animal | food_eaten |
| 1 | dog | 10 |
| 2 | cat | 13 |
| 3 | dog | 10 |
select animal, sum(food_eaten) as total_food_eaten from animals group by animal;
will give you
| animal | total_food_eaten |
| dog | 20 |
| cat | 13 |
That is how group by works. It sections your queries by a field of non-unique values that you pick. so,
select sum(food_eaten) as total_food_eaten from animals;
will give you
|total_food_eaten|
| 33 |
second
A left join will return all your left tables values regardless of matches and will join to any right join tables with values that match. What I am sure of is the fact that you have three income rows associating with one user row. When you do a left join this generates three matching left join rows. When you then left join the debt row to these three rows it can associate to all three, since the ID matches. This is what is giving you a three-pete. I suggest, if you are only looking for the sum for both I suggest splitting up the queries seeing as the income and debt tables want to have no association with each other in these tables.
This is a likely answer to help you along the way.
Multiple select statements in Single query

MySQL: If select in table X is empty, do select in table Y

in one query I would like to select information from table X.
however if table X doesn't return any information I would like to retrieve data from table Y.
Apart from each other the queries would look like this:
SELECT * FROM tableY WHERE user_id=1
SELECT * FROM tableX WHERE id=1
I tried the following to combine this, but it doesn't seem to work
SELECT * FROM tableY WHERE user_id=
IF (EXISTS (SELECT * FROM tableX WHERE id=1), 1, 0)
and of course the other way around
SELECT * FROM tableX WHERE id=
IF (EXISTS (SELECT * FROM tableY WHERE user_id=1), 1, 0)
Bot versions will only execute the first query, but not the second.
So I am kinda stuck here.
I also tried this, but as the tables do not have the same rows this shouldn't work... and thats correct it doesn't work:
SELECT *
FROM orbib.billing_address
WHERE user_id=1
UNION ALL
SELECT *
FROM orbib.users
WHERE id=1
AND NOT EXISTS
(SELECT *
FROM orbib.billing_address
WHERE user_id=1
)
Also tried doing this with a procedure as explained here:
However this didn't help as well, besides that it looks like the procedure is saved, causing the user id to always be 1, and this of course varies.
Maybe anybody has an idea how to create a query which does do what I want?
EDITS:
Here are table descriptions:
tableX:
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
username varchar(30) NO UNI NULL
firstname varchar(45) YES NULL
lastname varchar(45) YES NULL
street varchar(45) YES NULL
street_nr varchar(10) YES NULL
zipcode varchar(10) YES NULL
city varchar(45) YES NULL
password varchar(255) NO NULL
salt varchar(255) NO UNI NULL
email varchar(255) NO NULL
create_time datetime NO CURRENT_TIMESTAMP
company varchar(45) YES NULL
branche varchar(45) YES NULL
tableY:
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
user_id int(11) NO NULL
company varchar(45) YES NULL
contact_name varchar(100) YES NULL
street varchar(45) YES NULL
street_nr varchar(10) YES NULL
zipcode varchar(45) YES NULL
city varchar(45) YES NULL
terms_ok tinyint(1) YES NULL
billing_ok tinyint(1) YES NULL
So from the idea from #kickstart I tried to do this:
SELECT
IFNULL(tableY.company, tableX.company) company,
IFNULL(tableY.contact_name, tableX.lastname) contact,
IFNULL(tableY.street, tableX.street) street,
IFNULL(tableY.street_nr, tableX.street_nr) street_nr,
IFNULL(tableY.zipcode, tableX.zipcode) zipcode,
IFNULL(tableY.city, tableX.city) city
FROM (SELECT * FROM tableX) x
LEFT OUTER JOIN tableY ON tableY.user_id=1
LEFT OUTER JOIN tableX ON tableX.id=1
This gave me the error: 1248 Every derived table must have its own alias.
But found the solution I forgot the x in the FROM (SELECT)
After changing this it worked, resulting on two rows however, so I need to change this a bit.
Tnx #kickstarter
Making a major assumption that this is to return a single row, then possibly have a sub query to generate a single row and then LEFT OUTER JOIN the other 2 tables to that row.
Then you can use a load of IF statements to decide which tables values to return.
Efficiency is not likely to be its strong point!
SELECT IF(tableY.user_id IS NULL, tableX.id, tableY.user_id) AS id
IF(tableY.user_id IS NULL, tableX.field2, tableY.other_field2) AS field2,
etc
FROM (SELECT 1 AS dummy) a
LEFT OUTER JOIN tableY ON tableY.user_id = 1
LEFT OUTER JOIN tableX ON tableX.id = 1

How to INNER JOIN around a loop of tables

I have four tables as follows:
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE IF NOT EXISTS `categories_friends` (
`category_id` int(10) unsigned NOT NULL,
`friend_id` int(10) unsigned NOT NULL,
UNIQUE KEY `category_id` (`friend_id`,`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `friends` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`friend_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`,`friend_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE IF NOT EXISTS `ratings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`title` varchar(255) NOT NULL,
`description` text NOT NULL,
`rating` tinyint(2) unsigned NOT NULL,
`public` tinyint(1) NOT NULL DEFAULT '0',
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
I am trying to perform the following query on those tables:
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
INNER JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`category_id` = `Rating`.`category_id`
AND `JCategoriesFriend`.`friend_id` = `JFriend`.`id`)
INNER JOIN `favred`.`categories` AS `JCategory`
ON (`JCategory`.`id` = `Rating`.`category_id`
AND `JCategory`.`id` = `JCategoriesFriend`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `Rating`.`user_id` <> 1
AND `JCategory`.`id` IN (4, 14)
GROUP BY `Rating`.`id`
The query above is not working, as it returns no results (although there is data in the tables that should return), what I'm trying to do is to find all the Ratings that were not authored by me (ID:1), but were authored by my Friends, but only if I've selected to view a specific Category for that Friend, with the resulting set being filtered by a given set of specific Categories.
The INNER JOINs loop around through Rating --> Friend --> CategoriesFreind --> Category --> back to Rating.
If I remove the additional portion of the INNER JOIN's ON clauses as follows:
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
INNER JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`friend_id` = `JFriend`.`id`)
INNER JOIN `favred`.`categories` AS `JCategory`
ON (`JCategory`.`id` = `JCategoriesFriend`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `Rating`.`user_id` <> 1
AND `JCategory`.`id` IN (4, 14)
GROUP BY `Rating`.`id`
then the query will return results, but because the INNER JOIN joining the CategoriesFriend to the Rating is not being filtered by the 'JCategory'.'id' IN (4, 14) clause, it returns all Ratings by that friend instead of filtered as it should be.
Any suggestions on how to modify my query to get it to pull the filtered results?
And I'm using CakePHP, so a query that would fit into it's unique query format would be preferred although not required.
first ,why are you use the JFriend.id, does it mean something,or is it as the same as user_id?
try this one,the same logic but it's from top to bottom ,I feel:
SELECT * FROM categories as JCategory
INNER JOIN categories_friends as JCategoriesFriend ON JCategoriesFriend.category_id = JCategory.id
INNER JOIN friends AS JFriend ON JFriend.friend_id = JCategoriesFriend.friend_id
INNER JOIN ratings AS Rating ON Rating.user_id = JFriend.friend_id
WHERE JCategory.id IN (4,14) AND JFriend.user_id = 1 AND Rating.user_id <> 1 GROUP BY Rating.id
I got one result from all the data that I made for the testing.
if it does not work also,try make some correct data,maybe the data is not right...
the testing data below:
categories: id | name (14| 141414)
categories_friends: category_id| friend_id (14| 2)
friends: id | user_id | friend_id (4| 1| 2)
ratings: id | user_id | category_id | title (2| 2| 14 | 'haha')
So I wondered if the INNER JOINs were being a little too limiting and specific in their ON clauses. So I thought that maybe a LEFT JOIN would work better...
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
LEFT JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`friend_id` = `JFriend`.`id`
AND `JCategoriesFriend`.`category_id` = `Rating`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `JRatingsUser`.`id` IS NULL
AND `Rating`.`user_id` <> 1
GROUP BY `Rating`.`id`
That query worked for me.
I did away with linking to the categories table directly, and linked indirectly through the categories_friends table which sped up the query a little bit, and everything is working great.