MySQL - Computing the AVG(DISTINCT) of a relation - mysql

Column B of a relation has the following list of values in the five rows of the table:
3, NULL, 2, 3, 5
Which of the following is the correct value of AVG(DISTINCT B)?
I have tried creating a relational table here with the specified rows and then executed AVG(DISTINCT A): http://ideone.com/3ItE01
CREATE TABLE A(a int(8), b int(8), c int(8), d int(8), e int(8));
INSERT INTO A VALUES (3, NULL, 2, 3, 5);
INSERT INTO A VALUES (3, NULL, 2, 3, 5);
INSERT INTO A VALUES (3, NULL, 2, 3, 5);
INSERT INTO A VALUES (3, NULL, 2, 3, 5);
INSERT INTO A VALUES (3, NULL, 2, 3, 5);
But my SQL Query of "AVG(DISTINCT A)" is not valid. I am new to SQL and looking for documentation. Any ideas?

Create table like this
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`value` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
Insert values with query
insert into `test`(`id`,`value`) values (1,'3'),(2,'2'),(3,'3'),(4,NULL),(5,'5');
now use query
SELECT AVG( DISTINCT test.value)FROM test
to calculate the average you will get the result 3.3333333333333335

Related

Struggling to SELECT all elements from a table

MySQL is a new language to me and I struggle with selecting more data from my loans table when I do this query:
My objective is to print all elements of the Loans table that match the Bank IDs, all I get is outputs 1-10 where I have over 13 elements in my loans table.
EDIT 1: Bank Table serves as a link between all tables, I know the problem resides in my DML query however cluelessly not sure what to do.
When running my query, only matching primary key to foreign key appears. That is if Bank ID is 1 and Loans ID is 1 it shows, but when Bank ID is 1 and Loans ID is 13 it does not appear in the query.
Please save your criticism, as mentioned above, my experience is green.
My DML:
SELECT bank.bankID, bankcustomer.FirstName, bankcustomer.LastName, loans.FirstPaymentDate
FROM bank
JOIN bankcustomer ON bank.bankID = bankcustomer.customerID
JOIN loans ON loans.LoansID = bank.bankID;
Tables DDL:
CREATE TABLE bankCustomer(
CustomerID int(11) NOT NULL AUTO_INCREMENT,
FirstName varchar(20) DEFAULT NULL,
MiddleName varchar(20) DEFAULT NULL,
LastName varchar(20) DEFAULT NULL,
Address_Line1 varchar(50) DEFAULT NULL,
Address_Line2 varchar(50) DEFAULT NULL,
City varchar(20) DEFAULT NULL,
Region varchar(20) DEFAULT NULL,
PostCode varchar(20) DEFAULT NULL,
Country varchar(30) DEFAULT NULL,
DateOfBirth DATE DEFAULT NULL,
telephoneNumber int(13) DEFAULT 0,
openingAccount int CHECK (openingAccount >= 50),
PRIMARY KEY (CustomerID),
KEY CustomerID (CustomerID)
) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE bank(
BankID int(11) NOT NULL AUTO_INCREMENT,
customerID int,
PRIMARY KEY (BankID),
FOREIGN KEY (CustomerID) REFERENCES bankCustomer(CustomerID) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE loans(
LoansID int(11) NOT NULL AUTO_INCREMENT,
BankID int,
PaymentRate int(100) DEFAULT 300,
NumOfMonthlyPayments int(12) DEFAULT NULL,
FirstPaymentDate DATE DEFAULT NULL,
MonthlyDueDate DATE DEFAULT NULL,
PRIMARY KEY (LoansID),
FOREIGN KEY (BankID) REFERENCES bank(BankID) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
INSERT DML's:
INSERT INTO bank (BankID, CustomerID) VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (10, 10);
INSERT INTO loans (LoansID, BankID, PaymentRate, NumOfMonthlyPayments, FirstPaymentDate, MonthlyDueDate) VALUES (1, 1, 400, 12, '2008-02-03', '2008-03-25'),
(11, 1, 150, 10, '2008-02-04', '2008-04-25'),
(12, 1, 150, 10, '2008-02-07', '2008-04-25'),
(2, 2, 100, 20, '2011-04-01', '2011-04-25'),
(3, 3, 85, 5, '2015-07-03', '2015-08-25')...
Thank you all for your dear help, I managed to resolve my issue. The problem was the order of JOINing clauses.
SELECT loans.LoansID, bankcustomer.FirstName, customerbankcard.AccountNumber, loans.FirstPaymentDate
FROM bank
JOIN loans ON loans.BankID = bank.bankID
JOIN bankcustomer ON bankcustomer.customerID = bank.customerID
JOIN customerbankcard ON customerbankcard.bankID = bank.bankID
GROUP BY loans.LoansID ASC;
The outcome was to avoid loop, repeating wrongly assigned account numbers with customers whose IDs did not match.
If you want to select all tables use *. Also, you are joining tables incorrectly.
SELECT bank.*, bankcustomer.*, loans.*
FROM bank
JOIN bankcustomer ON bank.customerID = bankcustomer.customerID --Since you want to join data on customer ID you select custemerID in both tables
JOIN loans ON loans.BankID = bank.bankID; --The same problem here when joining tables
Goodluck and happy coding!
Firstly, joins could only be used between the tables when the columns are common between them (though they might have different names in different tables). That is why the concept of foreign key is of paramount importance as it references the column to the referenced table as you have duly done in your DDL commands.
Secondly, try using semicolon (;) as it denotes the end of any command and might get you out of the looping.

Calculating three differents sum in three tables

I have these tables:
DROP TABLE IF EXISTS books;
CREATE TABLE `books` (
`bookId` mediumint(8) UNSIGNED NOT NULL,
`title` varchar(10) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `books`
ADD PRIMARY KEY (`bookId`),
DROP TABLE IF EXISTS movements;
CREATE TABLE `movements` (
`movementId` mediumint(8) UNSIGNED NOT NULL,
`movementTypeId` tinyint(3) UNSIGNED NOT NULL,
`deletedFlag` tinyint(3) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `movements`
ADD PRIMARY KEY (`movementId`),
ADD KEY `movementId` (`movementTypeId`,`deletedFlag`) USING BTREE;
DROP TABLE IF EXISTS movements_types;
CREATE TABLE `movements_types` (
`movementTypeId` mediumint(8) UNSIGNED NOT NULL,
`title` varchar(200) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `movements_types`
ADD PRIMARY KEY (`movementTypeId`);
DROP TABLE IF EXISTS movements_books;
CREATE TABLE `movements_books` (
`movementId` mediumint(8) UNSIGNED NOT NULL,
`bookId` mediumint(8) UNSIGNED NOT NULL,
`bookSize` tinyint(3) UNSIGNED NOT NULL,
`quantity` smallint(5) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `books` (`bookId`, `title`) VALUES
(1, 'Harry Potter'),
(2, 'Mysql Join'),
(3, 'Comedy');
INSERT INTO `movements` (`movementId`, `movementTypeId`, `deletedFlag`) VALUES
(7, 1, 0),
(8, 2, 0),
(9, 2, 0);
INSERT INTO `movements_types` (`movementTypeId`, `title`) VALUES
(1, "Bought"),
(2, "Sold");
INSERT INTO `movements_books` (`movementId`, `bookId`, `bookSize`, `quantity`) VALUES
(7, 1, 1, 3),
(7, 1, 2, 3),
(7, 2, 1, 3),
(7, 2, 2, 3),
(8, 1, 1, 2),
(8, 1, 1, 2),
(9, 2, 1, 3);
bookSize is just an integer indicating the size of the book.
movements_books actually has 111824 records, movements has 4534.
deletedFlag is 1 for a deleted movement (I prefer to keep them flagged) and 0 otherwise.
I need help creating indexes and I need these results:
1) sizes sold/bought/available for each book (bookId, bookSize, booksSold, booksBought, booksBought minus booksSold)
2) books sold/bought/available for each book of all size (bookId, booksSold, booksBought, booksBought minus booksSold)
To get the one of the statistics I tried:
SELECT
books.title
movements_books_grouped.bookId,
SUM(IF(movements.movementTypeId=1, movements_books_grouped.quantity, NULL)) AS booksBought,
SUM(IF(movements.movementTypeId=2, movements_books_grouped.quantity, NULL)) AS booksSold,
(
SUM(IF(movements.movementTypeId=1, movements_books_grouped.quantity, 0))-
SUM(IF(movements.movementTypeId=2, movements_books_grouped.quantity, 0))
) AS booksAvailability,
FROM
(
SELECT bookId,quantity,movementId FROM movements_books GROUP BY bookId
) AS movements_books_grouped
JOIN movements ON movements.movementId=movements_books_grouped.movementId
JOIN books ON books.bookId=movements_books_grouped.bookId
GROUP BY movements_books_grouped.bookId
ORDER BY book.title
but it's very slow.
Edit: I needed to add another table to the example because that's the one that makes really slow the last query. I need to join to this table because I need to order the result by title.
Here's a query that can use indexes:
SELECT m.movementId
, m.movementTypeId
, m.deletedFlag
, mb.bookId
, mb.bookSize
, t.title
FROM movements m
JOIN movements_types t
ON t.movementTypeId = m.movementTypeId
JOIN movements_books mb
ON mb.movementid = m.movementid
WHERE m.deletedFlag=0;
An index on (m.movementTypeId, m.deletedFlag) may prove beneficial, but best to suck it and see.

MySQL. Average price, connecting two databases

I am learning MySQL and I currently do not understand how to do something.
I have two tables and I want to display some stuff out of it, it's pretty hard to explain so I'd rather show you.
These are my tables:
CREATE TABLE IF NOT EXISTS `proprietate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`serie_buletin` varchar(8) NOT NULL,
`cnp` bigint(20) NOT NULL,
`nr_vehicul` int(11) NOT NULL,
`data_cumpararii` date NOT NULL,
`pret` int(11) NOT NULL,
`id_persoana` int(11) NOT NULL,
PRIMARY KEY (id),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
CREATE TABLE IF NOT EXISTS `vehicul` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nr_vehicul` int(11) NOT NULL,
`marca` varchar(30) NOT NULL,
`id_marca` int(11) NOT NULL,
`tip` varchar(15) NOT NULL,
`culoare` varchar(15) NOT NULL,
`capacitate_cilindrica` int(11) NOT NULL,
`id_proprietate` int(11) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id_proprietate) REFERENCES proprietate(id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
And these are my values inside my tables:
INSERT INTO `proprietate` (`id`, `serie_buletin`, `cnp`, `nr_vehicul`, `data_cumpararii`, `pret`, `id_persoana`) VALUES
(1, 'AK162332', 2006036035087, 4, '2014-05-01', 35000, 1),
(2, 'AK162332', 2006036035087, 10, '2014-05-02', 90000, 2),
(3, 'AK176233', 6548751520125, 2, '2014-05-03', 55000, 3),
(4, 'BZ257743', 6548751520125, 2, '2014-05-04', 25000, 4),
(5, 'BZ257743', 2006036035087, 15, '2014-05-05', 63000, 5),
(6, 'DC456542', 2003564784513, 7, '2014-05-06', 30000, 6),
(7, 'EN654872', 2012654879521, 6, '2014-05-07', 50000, 7);
INSERT INTO `vehicul` (`id`, `nr_vehicul`, `marca`, `id_marca`, `tip`, `culoare`, `capacitate_cilindrica`, `id_proprietate`) VALUES
(1, 4, 'Mercedes', 1, 'CLK 350', 'negru', 3500, 1),
(2, 10, 'Mercedes', 1, 'S 500', 'silver', 5000, 2),
(3, 2, 'Mercedes', 1, 'ML 550', 'alb', 5500, 3),
(4, 2, 'BMW', 2, '325', 'galben', 2500, 4),
(5, 15, 'BMW', 2, 'X5', 'negru', 3500, 5),
(6, 7, 'Audi', 3, 'R5', 'mov', 5000, 6),
(7, 6, 'Audi', 3, 'Q5', 'metalic', 3000, 7);
What I want to display is:
marca | nr_vehicul | average_price
Audi | 13 | 40000
BMW | 17 | 44000
Mercedes | 16 | 60000
How can I do that? So far I have managed to display the first two columns but I have no idea how to reference the first table in the second and calculate the average price.
This is what I have so far:
SELECT marca, SUM(nr_vehicul) AS nr_vehicul FROM vehicul GROUP BY marca
Can anyone help me please?
You should join your tables to get combined information from both of them:
SELECT marca, SUM(vehicul.nr_vehicul) AS nr_vehicul, avg(pret) as pret
FROM vehicul
LEFT OUTER JOIN proprietate on (id_proprietate = proprietate.id)
GROUP BY marca;
see this sql fiddle session for the output.
First you select the data (column names with appropriate functions used) you need: marca, SUM(vehicul.nr_vehicul), AVG(pret), then you construct the joined structure from where mysql should retrieve these informations: vehicul, proprietate.
For this structure you need primarily the vehicul table, by which you will group the result set. You want to join the proprietate table to the vehicul table properly, to make sure the correct data structure is created. Since you have foreign key from one table to the other, the easiest way to do it is to use that key: LEFT OUTER JOIN proprietate on (id_proprietate = proprietate.id).
For more information on understanding the different JOIN types, please see this article by Craig Buckler.
$query = "SELECT type, AVG(pret) FROM vehicul GROUP BY marca";
$result = mysql_query($query) or die(mysql_error());
// Print out result
while($row = mysql_fetch_array($result)){
echo "The average price of ". $row['type']. " is $".$row['AVG(price)'];}</code>
should return the average price per marca

Most efficient way to count items under a nested tree

So I'm looking to provide a category (x) style product count on my website.
I'm currently using MySQL.
My categories table looks like:
Categories (Id, TreeLeft, TreeRight, Level, Name) - with 'Level' being the node depth.
Categories entered look like this:
My Item > Categories relation table looks like:
ItemCategories (ItemId, CategoryId)
Assuming I have:
1 item under 'TUBE'
2 items under 'LCD'
1 item under 'FLASH'
1 item under '2 WAY-RADIOs'
How can I most efficiently query my items (large db) + categories (4000 in db), to produce:
Electronics (5)
- Televisions (3)
- Tube (1)
- LCD (2)
- Portable Electronics (2)
- MP3 Players (1)
- Flash (1)
- 2 Way Radios (1)
Taking note to only return those categories which have products in them and also correctly counts them up the tree.
Any help most appreciated.
Edit: DB Code to recreate environment locally:
CREATE TABLE IF NOT EXISTS `Categories` (
`Id` int(11) NOT NULL auto_increment,
`TreeLeft` mediumint(7) NOT NULL,
`TreeRight` mediumint(7) NOT NULL,
`Level` tinyint(3) NOT NULL,
`Name` varchar(255) NOT NULL,
UNIQUE KEY `Id` (`Id`),
KEY `TreeLeft` (`TreeLeft`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
INSERT INTO `Categories` (`Id`, `TreeLeft`, `TreeRight`, `Level`, `Name`) VALUES
(1, 1, 20, 1, 'Electronics'),
(2, 2, 9, 2, 'Television'),
(3, 10, 19, 2, 'Portable Electronics'),
(4, 3, 4, 3, 'Tube'),
(5, 5, 6, 3, 'LCD'),
(6, 7, 8, 3, 'Plasma'),
(7, 11, 14, 3, 'MP3 Players'),
(8, 15, 16, 3, 'CD Players'),
(9, 11, 14, 3, '2 Way Radios'),
(10, 12, 13, 4, 'Flash');
CREATE TABLE IF NOT EXISTS `ItemCategories` (
`CategoryId` int(11) NOT NULL,
`ItemId` int(11) NOT NULL,
KEY `CategoryId` (`CategoryId`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `ItemCategories` (`CategoryId`, `ItemId`) VALUES
(4, 3442),
(5, 3441),
(5, 3456),
(9, 5343),
(10, 5423);
Please see the subsection, entitled Aggregate Functions in a Nested Set, of Mike Hillyer's classic article on this subject at Managing Hierarchical Data in MySQL

Mysql - Help me alter this search query to get desired results

Following is a dump of the tables and data needed to answer understand the system:-
The system consists of tutors and classes.
The data in the table All_Tag_Relations stores tag relations for each tutor registered and each class created by a tutor. The tag relations are used for searching classes.
CREATE TABLE IF NOT EXISTS `Tags` (
`id_tag` int(10) unsigned NOT NULL auto_increment,
`tag` varchar(255) default NULL,
PRIMARY KEY (`id_tag`),
UNIQUE KEY `tag` (`tag`),
KEY `id_tag` (`id_tag`),
KEY `tag_2` (`tag`),
KEY `tag_3` (`tag`),
KEY `tag_4` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `Tags` (`id_tag`, `tag`) VALUES
(1, 'Sandeepan'),
(2, 'Nath'),
(3, 'first'),
(4, 'class'),
(5, 'new'),
(6, 'Bob'),
(7, 'Cratchit');
CREATE TABLE IF NOT EXISTS `All_Tag_Relations` (
`id_tag` int(10) unsigned NOT NULL default '0',
`id_tutor` int(10) default NULL,
`id_wc` int(10) unsigned default NULL,
KEY `All_Tag_Relations_FKIndex1` (`id_tag`),
KEY `id_wc` (`id_wc`),
KEY `id_tag` (`id_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `All_Tag_Relations` (`id_tag`, `id_tutor`, `id_wc`) VALUES
(1, 1, NULL),
(2, 1, NULL),
(3, 1, 1),
(4, 1, 1),
(6, 2, NULL),
(7, 2, NULL),
(5, 2, 2),
(4, 2, 2),
(8, 1, 3),
(9, 1, 3);
Following is my query:-
This query searches for "first class" (tag for first = 3 and for class = 4, in Tags table) and returns all those classes such that both the terms first and class are present in the class name.
SELECT wtagrels.id_wc,SUM(DISTINCT( wtagrels.id_tag =3)) AS
key_1_total_matches,
SUM(DISTINCT( wtagrels.id_tag =4)) AS
key_2_total_matches
FROM all_tag_relations AS wtagrels
WHERE ( wtagrels.id_tag =3
OR wtagrels.id_tag =4 )
GROUP BY wtagrels.id_wc
HAVING key_1_total_matches = 1
AND key_2_total_matches = 1
LIMIT 0, 20
And it returns the class with id_wc = 1.
But, I want the search to show all those classes such that all the search terms are present in the class name or its tutor name
So that searching "Sandeepan class" (wtagrels.id_tag = 1,4) or "Sandeepan Nath" also returns the class with id_wc=1. And Searching. Searching "Bob First" should not return any classes.
Please modify the above query or suggest a new query, if possible using MyIsam - fulltext search, but somehow help me get the result.
I think this query would help you:
SET #tag1 = 1, #tag2 = 4; -- Setting some user variables to see where the ids go. (you can put the values in the query)
SELECT wtagrels.id_wc,
SUM(DISTINCT( wtagrels.id_tag =#tag1 OR wtagrels.id_tutor =#tag1)) AS key_1_total_matches,
SUM(DISTINCT( wtagrels.id_tag =#tag2 OR wtagrels.id_tutor =#tag2)) AS key_2_total_matches
FROM all_tag_relations AS wtagrels
WHERE ( wtagrels.id_tag =#tag1 OR wtagrels.id_tag =#tag2 )
GROUP BY wtagrels.id_wc
HAVING key_1_total_matches = 1 AND key_2_total_matches = 1
LIMIT 0, 20
It returns id_wc = 1.
For (6, 3) the query returns nothing.