MySql - Create view to read from Multiple Tables - mysql

I have archived some old line items for invoices that are no longer current but still need to reference them. I think I need to create a VIEW but not really understanding it. Can someone help so I can run a query to pull the invoice and then the total of all the line items assigned (no matter what table the items are in)?
CREATE TABLE `Invoice` (
`Invoice_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`Invoice_CreatedDateTime` DATETIME DEFAULT NULL,
`Invoice_Status` ENUM('Paid','Sent','Unsent','Hold') DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`)
) ENGINE=MYISAM DEFAULT CHARSET=latin1
CREATE TABLE `Invoice_LineItem` (
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
CREATE TABLE `Invoice_LineItem_Archived` (
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
Typically I would just run the following query to get the amount due on the invoices
SELECT
Invoice_ID,
Invoice_CreatedDateTime,
Invoice_Status,
(SELECT SUM(LineItem_Amount) AS totAmt FROM Invoice_LineItem WHERE LineItem_InvoiceID=Invoice_ID) AS Invoice_Total
FROM
Invoice
WHERE
Invoice_Status='Sent'
Also how can I select all the line items from both tables in one query?
SELECT
LineItem_ID,
LineItem_ChargeType,
LineItem_Amount
FROM
Invoice_LineItem
WHERE
LineItem_InvoiceID='1234'

You can use the MERGE Storage Engine to create a virtual table that's the union of two real tables:
CREATE TABLE Invoice_LineItem_All
(
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MERGE UNION=(Invoice_LineItem_Archived, Invoice_LineItem);

You can use UNION :
SELECT a.* FROM a
UNION
SELECT b.* FROM b;
You just need to have the same number and type of column in your different queries.
As far as I remember, you can add test in sub-queries, but I'm not sure you can order on the global result.
http://dev.mysql.com/doc/refman/4.1/en/union.html

Related

Partitioning large table by dates

I have implemented custom url shortener in my app and I have one table for that. table structure looks like this:
CREATE TABLE `urls` (
`id` int(11) NOT NULL,
`url_id` varchar(10) DEFAULT NULL,
`long_url` varchar(255) DEFAULT NULL,
`clicked` mediumint(5) NOT NULL DEFAULT 0,
`user_id` varchar(7) DEFAULT NULL,
`type` varchar(15) DEFAULT NULL,
`ad_id` int(11) DEFAULT NULL,
`campaign` int(11) DEFAULT,
`increment` tinyint(1) NOT NULL DEFAULT 0,
`date` date DEFAULT NULL,
`del` enum('1','0') NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
ALTER TABLE `urls`
ADD PRIMARY KEY (`id`),
ADD KEY `url_id` (`url_id`),
ADD KEY `type` (`type`),
ADD KEY `campaign` (`campaign`),
ADD KEY `ad_id` (`ad_id`),
ADD KEY `date` (`date`),
ADD KEY `user_id` (`user_id`);
The table now has 20.000.000 records and currently growing by 300k-400k records per day.
url_id column is unique varchar(10) and url looks like that: http://example.com/asdfghjklu
Now i have partitioned this table into 10 partitions by HASH(id):
PARTITION BY HASH (`id`)
PARTITIONS 10;
When I try to generate reports and join this table on others query is getting really slow, so slow even can't get 1 week report.
When I try to make big query in this table I filter almost every query with dates and I think it will be much better if I partition this table by date column.
Is it good idea?
As I read if I want to partition this table by date I need to add date in composite primary key: PRIMARY KEY(id, date)
What do you think about this? How do I improve my query performance?
I wold recommend use hash partition using date or month or YEAR
CREATE TABLE `urls` (
`id` int(11) NOT NULL,
`url_id` varchar(10) DEFAULT NULL,
`long_url` varchar(255) DEFAULT NULL,
`clicked` mediumint(5) NOT NULL DEFAULT 0,
`user_id` varchar(7) DEFAULT NULL,
`type` varchar(15) DEFAULT NULL,
`ad_id` int(11) DEFAULT NULL,
`campaign` int(11) DEFAULT,
`increment` tinyint(1) NOT NULL DEFAULT 0,
`date` date DEFAULT NULL,
`del` enum('1','0') NOT NULL DEFAULT '0',
PartitionsID int(4) unsigned NOT NULL,
KEY PartitionsID (PartitionsID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
PARTITION BY HASH (PartitionsID)
PARTITIONS 366;
IN PARTITION ID you just need to insert TO_DAYS(date) so you have only one value for entire day .
SOURCE
and it will make easy for partition for each day or you can do with month wise also depending on your data size .
for select
you can use below query as example
SELECT *
FROM TT ACT
WHERE ACT.CustomerID = vCustomerID
AND ACT.TransactionTime BETWEEN vInvoiceEndDate AND vPaymentDueDate
AND ACT.TrxnInfoTypeID IN (19, 23)
AND ACT.PaymentType = '1'
AND ACT.PartitionsID BETWEEN TO_DAYS(vInvoiceEndDate) AND TO_DAYS(vPaymentDueDate);

Insert into duplicate key and replace into does not work

CREATE TABLE `pv_network_coverage` (
`network_group_id` int(8) NOT NULL,
`carrier_group_id` int(8) NOT NULL,
`physician_count` int(8) NOT NULL DEFAULT '0',
`facility_count` int(8) NOT NULL DEFAULT '0',
`pcp_count` int(8) NOT NULL DEFAULT '0',
`update_time` datetime NOT NULL,
PRIMARY KEY (`network_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs;
REPLACE INTO pv_network_coverage(carrier_group_id,
network_group_id,
physician_count,
facility_count,
pcp_count,
update_time) SELECT *FROM temp_pv_network_coverage;
I use replace into and insert into with duplicate keys.
The physician_count should be 1000 but still 0..
It really makes me surprised.
Remember to select columns instead of select *from

MySQL use separate indices for JOIN and GROUP BY

I am trying to execute following query
SELECT
a.sessionID AS `sessionID`,
firstSeen, birthday, gender,
isAnonymous, LanguageCode
FROM transactions AS trx
INNER JOIN actions AS a ON a.sessionID = trx.SessionID
WHERE a.ActionType = 'PURCHASE'
GROUP BY trx.TransactionNumber
Explain provides the following output
1 SIMPLE trx ALL TransactionNumber,SessionID NULL NULL NULL 225036 Using temporary; Using filesort
1 SIMPLE a ref sessionID sessionID 98 infinitiExport.trx.SessionID 1 Using index
The problem is that I am trying to use one field for join and different field for GROUP BY.
How can I tell MySQL to use different indices for same table?
CREATE TABLE `transactions` (
`SessionID` varchar(32) NOT NULL DEFAULT '',
`date` datetime DEFAULT NULL,
`TransactionNumber` varchar(32) NOT NULL DEFAULT '',
`CustomerECommerceTrackID` int(11) DEFAULT NULL,
`SKU` varchar(45) DEFAULT NULL,
`AmountPaid` double DEFAULT NULL,
`Currency` varchar(10) DEFAULT NULL,
`Quantity` int(11) DEFAULT NULL,
`Name` tinytext NOT NULL,
`Category` varchar(45) NOT NULL DEFAULT '',
`customerInfoXML` text,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `TransactionNumber` (`TransactionNumber`),
KEY `SessionID` (`SessionID`)
) ENGINE=InnoDB AUTO_INCREMENT=212007 DEFAULT CHARSET=utf8;
CREATE TABLE `actions` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sessionActionDate` datetime DEFAULT NULL,
`actionURL` varchar(255) DEFAULT NULL,
`sessionID` varchar(32) NOT NULL DEFAULT '',
`ActionType` varchar(64) DEFAULT NULL,
`CustomerID` int(11) DEFAULT NULL,
`IPAddressID` int(11) DEFAULT NULL,
`CustomerDeviceID` int(11) DEFAULT NULL,
`customerInfoXML` text,
PRIMARY KEY (`id`),
KEY `ActionType` (`ActionType`),
KEY `CustomerDeviceID` (`CustomerDeviceID`),
KEY `sessionID` (`sessionID`)
) ENGINE=InnoDB AUTO_INCREMENT=15042833 DEFAULT CHARSET=utf8;
Thanks
EDIT 1: My indexes were broken, I had to add (SessionID, TransactionNumber) index to transactions table, however now, when I try to include trx.customerInfoXML table mysql stops using index
EDIT 2 Another answer does not really solved my problem because it's not standard sql syntax and generally not a good idea to force indices.
For ORM users such syntax is a unattainable luxury.
EDIT 3 I updated my indices and it solved the problem, see EDIT 1

Mysql Append table to add columns

I like to append a table to add column but without using alert table command
e.g.
This is the table which is missing some columns.
CREATE TABLE IF NOT EXISTS `admin` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`passwd` varchar(40) NOT NULL,
`isActive` tinyint(1) NOT NULL default '1',
`lastVisit` datetime NOT NULL default '0000-00-00 00:00:00',
`modifyAt` datetime NOT NULL,
`createdAt` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
So if i run this query then it should automatically add missing columns into my tables
CREATE TABLE IF NOT EXISTS `admin` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`passwd` varchar(40) NOT NULL,
`name` varchar(100) NOT NULL,
`originalUser` tinyint(1) NOT NULL default '0',
`isActive` tinyint(1) NOT NULL default '1',
`lastVisit` datetime NOT NULL default '0000-00-00 00:00:00',
`modifyAt` datetime NOT NULL,
`createdAt` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Can this be possible to do without using alert table command ?
I understand your question as you want to add some columns to your table. Please be informed that the term row is usually related to the actual data in your table, not the columns itself. If my assumption is wrong, please clarify your question.
You cannot use CREATE TABLE for altering a table. It is there to create table,
and if it cannot create it, it will in most cases throw an error like you described. Another command exists for that reason: ALTER TABLE.
You might do it something like this.
(1) Create your table with your CREATE TABLE syntax above:
CREATE TABLE IF NOT EXISTS `admin` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`passwd` varchar(40) NOT NULL,
`isActive` tinyint(1) NOT NULL default '1',
`lastVisit` datetime NOT NULL default '0000-00-00 00:00:00',
`modifyAt` datetime NOT NULL,
`createdAt` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
(2) Use ALTER TABLE like this to make the modifications I think you want to have in your second statement (two more columns):
ALTER TABLE
ADD COLUMN `name` varchar(100) NOT NULL AFTER `passwd`,
ADD COLUMN `originalUser` tinyint(1) NOT NULL default '0' AFTER `name`;
Not related to your question, but I'd avoid column names like name, because if you don't escape them properly it'll throw you other errors (see reserved words).

How to merge two tables based on common column and sort the results by date

I have two mysql tables and i want to merge the results of these two tables based on the common column rev_id. The merged results should be sorted by the date of two tables.
Please help me.
CREATE TABLE `reply` (
`id` int(3) NOT NULL auto_increment,
`name` varchar(25) NOT NULL default '',
`member_id` varchar(45) NOT NULL,
`rev_id` int(3) NOT NULL default '0',
`description` text,
`post_date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`flag` char(2) NOT NULL default 'N',
PRIMARY KEY (`id`),
KEY `member_id` (`member_id`)
) ENGINE=MyISAM;
CREATE TABLE `comment` (
`com_id` int(8) NOT NULL auto_increment,
`rev_id` int(5) NOT NULL default '0',
`member_id` varchar(50) NOT NULL,
`comm_desc` text NOT NULL,
`date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`com_id`),
KEY `member_id` (`member_id`)
) ENGINE=MyISAM;
Try this:
SELECT * FROM reply LEFT JOIN comment ON reply.rev_id = comment.rev_id ORDER BY reply.post_date, comment.date_created