Auto Increment two columns - php

I'm trying to auto increment the art_id in the table below based on the art_userid, Is this possible without writing any extra php code? The gen_id has to remain and cannot be removed. I'm using Mysql and Php
CREATE TABLE `articles` (
`gen_id` INT(10) NULL AUTO_INCREMENT,
`art_id` TINYINT(3) NULL DEFAULT '0',
`art_userid` INT(10) NULL DEFAULT '0',
`art_title` VARCHAR(150) NULL DEFAULT NULL,
PRIMARY KEY (`gen_id`)
So in the end, if user 1 posted an article, his art_id would be 1. The next one he posts would have the id 2.
But if user 2 posted and article, his art_id would be 1 again. The next one he posts would have the id 2. Not the continuation of the 1st users art_id.
gen_id | art_id | art_userid | art_title
-----------------------------------------
1 1 1 Title A
2 2 1 Title B
3 1 2 Title A
4 2 2 Title B
5 3 1 Title A

Your strategy to increment art_id is different than auto-increment. so you cant use default one in query. But You can write TRIGGER, which will update art_id ON INSERT using art_userid.

in that case you should do a table that links user and article with each id.
because here there is no autoincrement to do, it's just a data management :)
regards

a more common approach is
CREATE TABLE `articles` (
`id` INT AUTO_INCREMENT, -- entry in table
`gen_id` INT(10) NULL ,
`art_id` TINYINT(3) NULL DEFAULT '0',
`art_userid` INT(10) NULL DEFAULT '0',
`art_title` VARCHAR(150) NULL DEFAULT NULL,
PRIMARY KEY(`id`)
)
use an id column in table so you specifie entries increment total articles of a user by a query
UPDATE total_articles SET total_articles=total_articles+1 WHERE userid=1

Well, I kinda solved it, but with one less column. The engine type needs to be MyIsam for this. Then do a create like this:
CREATE TABLE `articles` (
`art_id` INT(10) NOT NULL AUTO_INCREMENT,
`art_userid` INT(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`art_userid`, `art_id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
Then when you insert art_userid, you'll get a unique value for art_id starting from 1 for each user.

Related

Mysql query to sort and merge two tables

I have two tables in my mysql database called forum_topics and forum_replies.
I am looking to have an overview of the latest posts / replies added, like this: http://prntscr.com/6ixtz4
to do so, i need a way to makee it sort by the time in both tables, and if a forum_reply is in the result it need to get its topic from the forum_topics.
How can i make this work? I have no mysql query to referer to to make this work.
CREATE TABLE IF NOT EXISTS `forum_topics` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`topic` varchar(255) NOT NULL,
`thread` varchar(255) NOT NULL,
`level` int(2) NOT NULL DEFAULT '0',
`creator` int(255) NOT NULL,
`time` varchar(255) NOT NULL,
`innlegg` text NOT NULL,
`ip` varchar(255) NOT NULL,
`locked` enum('yes','no') NOT NULL DEFAULT 'no',
`deleted` enum('yes','no') NOT NULL DEFAULT 'no',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
CREATE TABLE IF NOT EXISTS `forum_replies` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`topicid` int(255) NOT NULL,
`userid` int(255) NOT NULL,
`time` int(255) NOT NULL,
`reply` text NOT NULL,
`deleted` enum('yes','no') NOT NULL DEFAULT 'no',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=20 ;
exampledata:
in table forum_topics
id |topic| time|
1 | test | 10
2 | test2 | 29
in table forum replies:
id | topicid | time |
1 | 1 | 18
2 | 2 | 28
As in this example i would like the outcome to be sorted something like this:
10
18
28
29
if forum_replies is one of the results it would need some data from forum_topics, but if forum_topics is one of the results it wouldnt need any data from the forum_replies.
The topicid is the id from the forum_topics of the topic that the reply is a response to.
So in the end i want to create the example output as in the image.
EDIT:
it would be a result containing in following order:
10
18
28
29
By loading the data in the example data sets, this will get the time from both tables, but sort the time from both as if they were in one table. The below query gets the results, and then orders them in order of time. Since both tables have the same structure, you can "union" them together as if they were one table and sort by time using "order_by"
select time
from forum_topics
UNION
select time
from forum_replies
order by time
Note: I was able to load both tables in the above request but without the last line on each. In other words I trimmed the part referring to the engine, and then just created the tables, and then entered the data provided..
I'm sorry I have to say the table structure of a forum post is incorrect. In your case, you will be very hard to sort a post based on topic and reply. I would suggest a table structure like this:
CREATE TABLE IF NOT EXISTS `forum_topics` (
`tid` int(255) NOT NULL AUTO_INCREMENT, // Topic ID
`tsubject` varchar(255) NOT NULL, // Topic Subject
`level` int(2) NOT NULL DEFAULT '0',
`creator` int(255) NOT NULL,
`innlegg` text NOT NULL, // I don't know what this means ...
`locked` enum('yes','no') NOT NULL DEFAULT 'no',
`deleted` enum('yes','no') NOT NULL DEFAULT 'no',
PRIMARY KEY (`tid`),
UNIQUE KEY `id` (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5;
CREATE TABLE IF NOT EXISTS `forum_posts` (
`pid` int(255) NOT NULL AUTO_INCREMENT,
`tid` int(255) NOT NULL,
`userid` int(255) NOT NULL,
`time` int(255) NOT NULL,
`pcontent` text NOT NULL, // Post Content
`isauthorpost` int(1) NOT NULL, // Optional: If this is the first post of the topic
`deleted` enum('yes','no') NOT NULL DEFAULT 'no',
PRIMARY KEY (`pid`),
UNIQUE KEY `id` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=20 ;
So now you will have a topic id to follow by the first. And you can just search for all replies with ORDER BY pid, for the topic details, you can use LEFT JOIN forum_topics or INNER JOIN to finish.

update fields mysql table with value from other row for the same product id

I need to update a database table with value that is used in another row.
I have a database with 4000 products, for every product there are 3 rows, 1 for every language (i work with 3 languages).
Now i need to copy the product title from the dutch language into the title field from the English product row and the French product row for the same product id. Some title field in English and Frensh are empty, but not al off them are empty.
So I have this fields
product_id ;
language_id ;
product_title
Anyone can help me with the sql i need to have to do this for all my 4000 products?
Thank you, kind regards
Pete
ps_product_lang is the name of the product table
the database is MySQL
id_product int(10) unsigned NO PRI NULL
id_shop int(11) unsigned NO PRI 1
id_lang int(10) unsigned NO PRI NULL
description text YES NULL
description_short text YES NULL
link_rewrite varchar(128) NO NULL
meta_description varchar(255) YES NULL
meta_keywords varchar(255) YES NULL
meta_title varchar(128) YES NULL
name varchar(128) NO MUL NULL
available_now varchar(255) YES NULL
available_later varchar(255) YES NULL
Something along these lines should work.
UPDATE ps_product_lang p1
SET name =
(SELECT name
FROM (SELECT * FROM ps_product_lang) p2
WHERE p2.`id_product` = p1.`id_product`
AND p2.`id_lang` = 6)
WHERE `id_lang` != 6
You need the extra nested select in there to prevent MySQL from reporting the following error:
Error Code: 1093
You can't specify target table 'p1' for update in FROM clause

Combining two result sets from mysql

So I know that there are several many posts on this topic on this website, and the closest one I could find that was similar was:
Can I take the results from two rows and combine them into one?
I am working on a project that involves 'accounts receivables' and 'accounts payable', but that both of those need data in a single list:
date | description | reference | debit | credit
I have read about the mySQL UNION statement being used to combine two result sets into one, however, it also appears that the two results sets must match in column count and type according to the below website:
http://www.w3schools.com/sql/sql_union.asp
The problem I'm facing is that the two result sets don't have the same column count as the information for one doesn't directly correlate to the other (which will exclude the use of the UNION statement). What would be the best practice at acquiring the data from the two tables and sort them based on date? I'll include my SQL calls below as reference:
Accounts Receivable:
SELECT tblARP.*,tblAR.invoiceID,tblAR.ledgerID
FROM Accounting_ReceivablesPayments tblARP
INNER JOIN Accounting_Receivables tblAR ON tblARP.invoiceID = tblAR.invoiceID
ORDER BY deposited
Accounts Payable:
SELECT tblAPP.*,tblAP.id,tblAP.ledgerID,tblAP.tblName,tblAP.rowID,tblAP.invoice
FROM Accounting_PayablesPayments tblAPP
INNER JOIN Accounting_Payables tblAP ON tblAPP.payablesID = tblAP.id
ORDER BY deposited
UPDATE
Per the requests in the comments, here are the columns for the tables:
Accounting_Receivables
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT UNIQUE,
invoiceID BIGINT NOT NULL,
amount DECIMAL(9,2) NOT NULL DEFAULT '1.00',
ledgerID BIGINT NOT NULL,
note TEXT
Accounting_ReceivablesPayments
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT UNIQUE,
invoiceID BIGINT NOT NULL,
received DATE NOT NULL,
type VARCHAR(10) NOT NULL,
amount DECIMAL(9,2) NOT NULL DEFAULT '1.00',
deposited DATE,
tag VARCHAR(32) NOT NULL
Accounting_Payables
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT UNIQUE,
paid TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
invoice BIGINT NOT NULL,
amount DECIMAL(9,2) NOT NULL DEFAULT '1.00',
terms VARCHAR(3) NOT NULL DEFAULT 'net',
due DATE,
tblName VARCHAR(48) NOT NULL,
rowID BIGINT NOT NULL,
ledgerID BIGINT NOT NULL,
note TEXT
Accounting_PayablesPayments
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT UNIQUE,
payablesID BIGINT NOT NULL,
created DATE NOT NULL,
type VARCHAR(10) NOT NULL,
amount DECIMAL(9,2) NOT NULL DEFAULT '1.00',
deposited DATE,
tag VARCHAR(32) NOT NULL
to what I was saying in the comments you should do this
( SELECT
tblARP.*,
tblAR.invoiceID,
tblAR.ledgerID,
NULL, -- # -- null values for your rows to match columns
NULL,
NULL
FROM `Accounting_ReceivablesPayments` tblARP
INNER JOIN `Accounting_Receivables` tblAR ON tblARP.invoiceID = tblAR.invoiceID
ORDER BY deposited
)
UNION ALL -- # -- union all to include everything
( SELECT
tblAPP.*,
tblAP.id,
tblAP.ledgerID,
tblAP.tblName,
tblAP.rowID,
tblAP.invoice
FROM `Accounting_PayablesPayments` tblAPP
INNER JOIN `Accounting_Payables` tblAP ON tblAPP.payablesID = tblAP.id
ORDER BY deposited
)

mysql - php - Need to get only the latest record from a self referencing data

Hi,
I need some help with SQL. Attached is the image of my table.
If you see rootmessageid column there are 4 records of 99s. All these 4 makes one complete conversation.
Similarly the 2 records of 119 makes an other conversation.
116, 117, 118 are single message conversation.
Now I need to get all the records where msgfrom = 7 or msgto = 7 (this was the easy part)
Now the complicated bit. I want the only the latest record (based on datetimecreated) from each conversation.
Following the script to create this table.
CREATE TABLE IF NOT EXISTS `selectioncommunication` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`comactionid` int(11) NOT NULL,
`usercomment` varchar(2048) DEFAULT NULL,
`msgfrom` int(11) NOT NULL,
`msgto` int(11) NOT NULL,
`projectid` int(11) NOT NULL,
`parentmessageid` int(11) NOT NULL,
`datetimecreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`rootmessageid` int(11) NOT NULL,
`isread` tinyint(1) NOT NULL DEFAULT '0',
`isclosed` tinyint(1) DEFAULT '0',
`relative_date_time` datetime DEFAULT NULL,
`consultant_response` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=121 );
You want the groupwise maximum:
SELECT s.*
FROM selectioncommunication s NATURAL JOIN (
SELECT parentmessageid, MAX(datetimecreated) datetimecreated
FROM selectioncommunication
WHERE msgfrom = 7 OR msgto = 7
GROUP BY parentmessageid
) t
WHERE s.msgfrom = 7 OR s.msgto = 7
use ORDER BY datetime ASC/DESC
this will sort your results in order then add LIMIT 1 to the end of your query to only get the first record in your list.
Here is your SQl Fiddle without Join
SELECT *
FROM selectioncommunication k
WHERE datetimecreated = (SELECT
MAX(datetimecreated)
FROM selectioncommunication s
WHERE s.rootmessageid = k.rootmessageid
GROUP BY s.rootmessageid
ORDER BY s.id)

Optimize this query further? - indexed but still slow

I have a query below that joins 4 tables. I have added indexes and the explain output looks good with indexes used (see below).
Can I optimize the query further?
The modelXml is rather big on some records.For a big project where I get back 22 records, each with approximately 2.5 - 3MB of modelXml data, the query is taking long (total of 69MB of data returned).
I suspect this is the issue but not sure how to deal with it.
I was reading on adjusting internal mysql variables e.g key_buffer_size and table_cache. Would any of this help?
key_buffer_size is currently set at 8384512 (~8MB) and table_cache at 64
What should I increase it to?
What other variables should I be looking at to manage to speed up return of such big data?
Any other suggestions are welcome. I am a novice to mysql but really trying to get better.
SELECT `m`.`modelId`, `m`.`modelTypeId`, `m`.`modelXml`, `m`.`xmlSize`, `m`.`createdById`, `m`.`creationDate`, `m`.`modifiedDate`, `u`.`firstName`, `u`.`lastName` FROM `models_1` AS `m`
INNER JOIN `modelFolderAssociations_1` AS `mfa` ON m.modelId = mfa.modelIOId
INNER JOIN `modelFolders_1` AS `mf` ON mfa.folderId = mf.folderId
INNER JOIN `users_1` AS `u` ON m.createdById = u.userId
WHERE (m.projectId = 2) AND (mfa.folderId = 5) AND (mfa.modelIOType = 2) AND (m.modelTypeId = 2)
CREATE TABLE `models` (
`modelId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`groupId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`createdById` int(11) NOT NULL,
`modelTypeId` int(11) NOT NULL,
`modelXml` longtext,
`modelSpecXml` longtext NOT NULL,
`xmlSize` bigint(20) NOT NULL default '0',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`modelId`,`customerId`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8
CREATE TABLE `modelFolders` (
`folderId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`groupId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`parentId` int(11) NOT NULL,
`folderName` varchar(64) NOT NULL,
`folderType` int(11) NOT NULL,
`editable` tinyint(1) NOT NULL default '1',
`nextDefaultNameNumber` int(11) NOT NULL default '1',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`folderId`,`customerId`),
KEY `parentId` (`parentId`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
CREATE TABLE `modelFolderAssociations` (
`associationId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`folderId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`modelIOId` int(11) NOT NULL,
`modelIOType` tinyint(1) NOT NULL default '1',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`associationId`,`customerId`),
KEY `folderId` (`folderId`,`modelIOType`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8
CREATE TABLE `users` (
`userId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`userName` varchar(50) NOT NULL,
`password` varchar(256) NOT NULL,
`firstName` varchar(50) default NULL,
`lastName` varchar(50) default NULL,
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`userId`,`customerId`),
UNIQUE KEY `userName` (`userName`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
Explain output
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
| 1 | SIMPLE | modelFolders | const | PRIMARY | PRIMARY | 8 | const,const | 1 | Using index |
| 1 | SIMPLE | modelFolderAssociations | ref | folderId | folderId | 5 | const,const | 22 | Using where |
| 1 | SIMPLE | models | eq_ref | PRIMARY | PRIMARY | 8 | xa_system.modelFolderAssociations.modelIOId,const | 1 | Using where |
| 1 | SIMPLE | users | eq_ref | PRIMARY | PRIMARY | 8 | xa_system.models.createdById,const | 1 | |
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
Having large text columns, like those you're using to store XML I presume, can hurt performance regardless of how well your indexes are structured.
It can be better in these cases to move the text columns to a separate table, indexed by string length which you're already storing and CRC32.
CREATE TABLE MODEL_XML (
xmlId INT(11) unsigned NOT NULL auto_increment,
xmlSize BIGINT(20) NOT NULL default '0',
crc32 INT(11) unsigned NOT NULL,
xmlData LONGTEXT,
PRIMARY KEY (xmlId),
UNIQUE KEY (xmlSize, crc32)
)
Then the width of your columns on the table with your important indices becomes constant.
ex.
modelXmlId INT(11) unsigned NOT NULL
specXmlId INT(11) unsigned NOT NULL
It also has the benefit of being more space-efficient for redundant text (empty strings, etc) since they would all share one xmlId and thus one row in the DB.
You should index your foreign keys, this will really help with your joins:
CREATE INDEX IDX_MODELS_CUSTID
on models (customerId)
CREATE INDEX IDX_FLDR_ASSOC_MODELIO
modelFolderAssociations(modelIOId)
CREATE INDEX IDX_FLDR_ASSOC_FLDRID
modelFolderAssociations(folderId)
and so on.
Test your query after taking off the modelXml column from the SELECT clause.
If the speed is then significantly better, then the slowness comes from the volume off data to transfer, not the query itself.
Your indexes don't always match the queries and joins. If all of the columns in your WHERE and JOIN clauses are not in the index, you're forcing mysql to look at the underlying row, which will kill your performance, especially since your model rows are so wide.
For "modelFolderAssociations", you made the correct composite key for the where clause, but you should include modelIOId for the join to model.
For "models", you'd want a composite index on (modelId, projectId, modelTypeId, createdById ) to cover the incoming link from mfa, the two items in the where clause, and the outbound link to users.
For "modelFolders" and "users", you have the incoming join covered in your primary keys.
The engine is only going to use one index, so adding extra index single indexes (as Mike suggested) won't be as good.

Categories