User and game database many-to-many connection - mysql

I'm trying to create a game database. I have already created a user table where the users, password and email are stored.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` char(40) DEFAULT NULL,
`email` varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8;
I have also created a games table where the game type, name of the game, duration, description, active and who has created the game.
CREATE TABLE `games` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(30) DEFAULT NULL,
`name` varchar(60) DEFAULT NULL,
`duration` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`description` varchar(255) DEFAULT NULL,
`Active` tinyint(1) DEFAULT NULL,
`Completed` tinyint(1) DEFAULT NULL,
`createdBy` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
The users will be able to create a game and invite x number of users, hence it will be a many-to-many relations. I have tried to create a table called active_games but I'm not sure how I should proceed. I need a connection so that I know who has created the game and who is playing that game.
CREATE TABLE `active_games` (
`user_id` int(11) NOT NULL DEFAULT '0',
`game_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`,`game_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
What would be the next step? If a user creates a game and sends the "invite" to other friends, is it possible to automatically assign a game ID and the users invited to the that game ID? And if I want to find all the active games for a specific user, how can I do that?

You need two more tables. UserGames would have information about users who create games:
CREATE TABLE UserGames (
UserGameId int not null auto_increment primary key,
userid int NOT NULL references users(id),
gameid int not null references games(id),
CreationDate datetime,
. . .
);
And GameInvites:
CREATE TABLE GameInvites (
GameInviteId int not null auto_increment primary key,
UserGamesId int not null references UserGames(UserGamesId),
invited_userid int NOT NULL references users(id),
AcceptedFlag bit
. . .
);
The . . . represent additional information that might want to store about each relationship.

Related

i have a challenge relating what should be primary key and foreign key in my database tables

i am designing database tables for a real estate company. my head is clogged up .i cant figure out how to decide which columns will become primary keys,foreign keys and/or composite keys.
i have four tables; location, floors , typeOfProperty and features.
location table is the most basic table that has columns; locationLong, locationLat,locationName and propertyName. locationlong is the primary key in this table.
i created the location table and used locationlong as primary key because i figured out that every point on earth has a unique location Longitude.this is if i consider that positive and negative values are always unique.(i stand to be collected).
i have noted however that there are situations where i would want to identify a property on a certain location that has a building that has more than one floor.therefore i would like to figure out how my floors table needs to be constructed. i am thinking of having a location long column and a second
column called floor number such that both these columns will make composite primary key of this table.
There is a third table called typeOfProperty. this is the table where i want to have different columns that select the type of property that can be on a particular floor. i.e a floor can have many houses to buy, many houses to let, a commercial property to sell, etc. so i have created the following columns;
hseBuyOrLetOrFurn ENUM('buy', 'let', 'furn') - SELECT IF HOUSE IS TO BUY, LET,
OR FULLY FURNISHED
comspaceBuyOrLease ENUM('buy', 'lease') - TO SELECT IF COMMERCIAL SPACE IS BUY
OR LEASE
cost INT -- TO CAPTURE COST OF PROPERTY ETC.
i would want to know what to use as primary key in this table.
there is a third table called general features . this table has columns that has columns that show the features of a particular type of property e.g it has a column for No of bedrooms, cctv,swimming pool, bathrooms,lifts, etc.
i have other similar tables to the general features as shown in the code below.
please assist me to know how i should figure out primary and foreign keys in this table.
CREATE TABLE `location` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`locationName` varchar(35) NOT NULL,
`houseNumber` int(11) DEFAULT NULL,
PRIMARY KEY (`locationLong`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `floors` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`locationName` varchar(35) NOT NULL,
`id` int(11) DEFAULT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`ld`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `propertytype` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`hseBuyOrLetOrFurn` enum('buy','let','furn') DEFAULT NULL,
`bedrooms` int(11) DEFAULT NULL,
`gatedOrSloneOrApart` enum('gated','slone','apart') DEFAULT NULL,
`hotelOr` tinyint(4) DEFAULT NULL,
`gdwnBuyOrLease` enum('gdwn','lease') DEFAULT NULL,
`landBuyOrLease` enum('buy','lease') DEFAULT NULL,
`comspaceBuyOrLease` enum('buy','lease') DEFAULT NULL,
`twoDImage` blob,
`threeDImage` blob,
`vRVideo` blob,
`cost` int(10) unsigned NOT NULL,
`location_locationLong` decimal(11,8) NOT NULL,
PRIMARY KEY (`locationLong`),
KEY `fk_propertyType_location_idx` (`location_locationLong`),
CONSTRAINT `fk_propertyType_location` FOREIGN KEY (`location_locationLong`) REFERENCES `area` (`locationLong`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `generalfeatures` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`livingAreaAndSize` int(11) NOT NULL,
`bedrooms` int(11) NOT NULL,
`bathrooms` int(11) NOT NULL,
`masterEnsuite` tinyint(1) NOT NULL,
`bedroomsWithBathrooms` tinyint(4) NOT NULL,
`kitchenAndSize` tinyint(4) NOT NULL,
`parkingAndSlots` tinyint(4) NOT NULL,
`swimmingPool` tinyint(1) NOT NULL,
`liftsAndNumber` tinyint(4) NOT NULL,
`CCTV` tinyint(1) NOT NULL,
`sizeOfLand` int(11) NOT NULL,
`borehole` tinyint(1) NOT NULL,
`propertyType_locationLong` decimal(11,8) NOT NULL,
PRIMARY KEY (`locationLong`),
KEY `fk_generalFeatures_propertyType1_idx` (`propertyType_locationLong`),
CONSTRAINT `fk_generalFeatures_propertyType1` FOREIGN KEY (`propertyType_locationLong`) REFERENCES `propertytype` (`locationLong`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `hotelfeatures` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`conference` tinyint(1) NOT NULL,
`fibreCable` tinyint(1) NOT NULL,
`spa` tinyint(1) NOT NULL,
`freshOutdoor` tinyint(1) NOT NULL,
`laundryFacilities` tinyint(1) NOT NULL,
`entertainment` tinyint(1) NOT NULL,
`wifi` tinyint(1) NOT NULL,
`propertyType_locationLong` decimal(11,8) NOT NULL,
PRIMARY KEY (`locationLong`),
KEY `fk_hotelFeatures_propertyType1_idx` (`propertyType_locationLong`),
CONSTRAINT `fk_hotelFeatures_propertyType1` FOREIGN KEY (`propertyType_locationLong`) REFERENCES `propertytype` (`locationLong`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `outdoorfeatures` (
`locationLong` decimal(11,8) NOT NULL,
`locationLat` decimal(10,8) NOT NULL,
`gym` tinyint(1) NOT NULL,
`matureGardens` tinyint(1) NOT NULL,
`partyArea` tinyint(1) NOT NULL,
`gardenAndSize` tinyint(1) NOT NULL,
`waterFront` tinyint(1) NOT NULL,
`propertyType_locationLong` decimal(11,8) NOT NULL,
PRIMARY KEY (`locationLong`),
KEY `fk_outdoorFeatures_propertyType1_idx` (`propertyType_locationLong`),
CONSTRAINT `fk_outdoorFeatures_propertyType1` FOREIGN KEY (`propertyType_locationLong`) REFERENCES `propertytype` (`locationLong`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1
I want to have a general idea how the location table that have location details, links to floors table that has details of floor type links to the propertytype table that links to different property type and finally how this property type table links to the generalfeatures, hotel features and indoor features table.
You have a table to hold property main data (this table later you add to it more fields as required until I get the final design for table)
Ex: main_property_file( property_id PK , address, GPS_location )
Then you need to know is it for lease or sale ,
Build lookup table hold this , ex: property_for(typefor PK, name this)
And going to add a filed in previous main_property_file for typefor filed as foreign key
And so on until you put all business data structure , then going to review the tables and relation for consistency, you can put this in visual tool if you cannot imagine the relation and the data each table hold, and finally ask your model with query to find information or enter new data and so on to be sure your table design is complete and review the constraints too.

MySQL move rows from one table to another by condition

We have a MySQL database of users, their sold and purchased products. We need to move inactive users who have not logged-in from last 3 years and never purchased or sold anything on our website to another table. Each table has millions of entries.
This is a table for sold items. Around 40m entries;
CREATE TABLE `sold` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`item` bigint(20) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is a table for purchased items. Around 6m entries;
CREATE TABLE `purchased` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`item` bigint(20) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is a user table, around 17m entries;
CREATE TABLE `users` (
`uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT '',
`email` varchar(64) DEFAULT NULL,
`lastlogin` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`),
UNIQUE KEY `email_index` (`email`),
KEY `lastlogin` (`lastlogin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is the table where we need to move inactive users to
CREATE TABLE `inactiveusers` (
`uid` int(10) unsigned NOT NULL,
`name` varchar(32) DEFAULT '',
`email` varchar(64) DEFAULT NULL,
`lastlogin` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`),
UNIQUE KEY `email_index` (`email`),
KEY `lastlogin` (`lastlogin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Any suggestions on how to achieve this with minimum downtime?
#Yumoji, I guess your probelm is How to calculate the last three 3 years of any activity. Right?
So, if that is the case then you should add a "created_at" column in your DB tables.
Now, after you add a created_at column in your tables you can easily calculate last three years activity.
Here it is-
SELECT uid FROM sold AND purchased WHERE sold.created_at>DATE_SUB(NOW(), INTERVAL 3 YEAR) OR purchased.created_at>DATE_SUB(NOW(), INTERVAL 3 YEAR);
from this query you get the user ids, Then -
INSERT INTO inactiveusers select * from users where uid = 'the user ids u get';
DELETE FROM users where uid = 'the user ids u get';
I hope it solves problem. Cheers.

MySQL: Optimizing JOINs to find non-matching records

We have a host management system (let's call it CMDB), and a DNS system, each using different tables. The former syncs to the latter, but manual changes cause them to get out of sync. I would like to craft a query to find aliases in CMDB that do NOT have a matching entry in DNS (either no entry, or the name/IP is different)
Because of the large size of the tables, and the need for this query to run frequently, optimizing the query is very important.
Here's what the tables look like:
cmdb_record: id, ipaddr
cmdb_alias: record_id, host_alias
dns_entry: name, ipaddr
cmdb_alias.record_id is a foreign key from cmdb_record.id, so that one IP address can have multiple aliases.
So far, here's what I've come up with:
SELECT cmdb_alias.host_alias, cmdb_record.ipaddr
FROM cmdb_record
INNER JOIN cmdb_alias ON cmdb_alias.record_id = cmdb_record.id
LEFT JOIN dns_entry
ON dns_entry.ipaddr = cmdb_record.ipaddr
AND dns_entry.name = cmdb_alias.host_alias
WHERE dns_entry.ipaddr IS NULL OR dns_entry.name IS NULL
This seems to work, but takes a very long time to run. Is there a better way to do this? Thanks!
EDIT: As requested, here are the SHOW CREATE TABLEs. There are lots of extra fields that aren't particularly relevant, but included for completeness.
Create Table: CREATE TABLE `cmdb_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip_version` int(11) DEFAULT NULL,
`ipaddr` varchar(40) DEFAULT NULL,
`ipaddr_numeric` decimal(40,0) DEFAULT NULL,
`block_id` int(11) NOT NULL,
`record_commented` tinyint(1) NOT NULL,
`mod_time` datetime NOT NULL,
`deleted` tinyint(1) NOT NULL,
`deleted_date` datetime DEFAULT NULL,
`record_owner` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ipaddr` (`ipaddr`),
KEY `cmdb_record_fe30f0f7` (`ipaddr`),
KEY `cmdb_record_2b8b575` (`ipaddr_numeric`),
KEY `cmdb_record_45897ef2` (`block_id`),
CONSTRAINT `block_id_refs_id_ed6ed320` FOREIGN KEY (`block_id`) REFERENCES `cmdb_block` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=104427 DEFAULT CHARSET=latin1
Create Table: CREATE TABLE `cmdb_alias` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`host_alias` varchar(255) COLLATE latin1_general_cs NOT NULL,
`record_id` int(11) NOT NULL,
`record_order` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `cmdb_alias_fcffc3bb` (`record_id`),
KEY `alias_lookup` (`host_alias`),
CONSTRAINT `record_id_refs_id_8169fc71` FOREIGN KEY (`record_id`) REFERENCES `cmdb_record` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=155433 DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs
Create Table: CREATE TABLE `dns_entry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rec_grp_id` varchar(40) NOT NULL,
`parent_id` int(11) NOT NULL,
`domain_id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`type` varchar(6) DEFAULT NULL,
`ipaddr` varchar(255) DEFAULT NULL,
`ttl` int(11) DEFAULT NULL,
`prio` int(11) DEFAULT NULL,
`status` varchar(20) NOT NULL,
`op` varchar(20) NOT NULL,
`mod_time` datetime NOT NULL,
`whodunit` varchar(50) NOT NULL,
`comments` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `dns_entry_a2431ea` (`domain_id`),
KEY `dns_entry_52094d6e` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=49437 DEFAULT CHARSET=utf8
If you don't have one already, create an index on dns_entry(ipaddr, name). This might be all you need to speed the query.

MySql - Create view to read from Multiple Tables

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

MySQL query: pull all the other categories minus the one that has been saved

I really need some help with forming a MySQL query that I just cannot work out. On my website I have a system in place that will hopefully remember some selections that user made when they last visited the site.
On the site the user can select which category they wish to read the content of next time they come to site. That setting will be remembered but the menu should be displayed slightly different. It should show all the other categories minus the one that has been saved.
So if I have these categories,
Blog
Inspiration
Case Studies
and the user saved Blog, the next time they come to the site the categories list should just be
Inspiration
Case Studies.
How can this data be pulled from the database?
Currently I have a table that identifies the user via a unique cookie id:
CREATE TABLE IF NOT EXISTS `cookieTable` (
`cookieEntryId` int(11) NOT NULL AUTO_INCREMENT,
`cookieId` varchar(32) NOT NULL,
`expirationDate` int(10) NOT NULL,
PRIMARY KEY (`cookieEntryId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
I have a category table
CREATE TABLE IF NOT EXISTS `categoryTable` (
`categoryId` int(11) NOT NULL AUTO_INCREMENT,
`categoryTitle` varchar(25) NOT NULL,
`categoryAbstract` varchar(150) NOT NULL,
`categorySlug` varchar(25) NOT NULL,
`categoryIsSpecial` int(1) DEFAULT NULL,
`categoryOnline` int(1) DEFAULT NULL,
`dashboardUserId` int(11) NOT NULL,
`categoryDateCreated` int(10) NOT NULL,
PRIMARY KEY (`categoryId`),
KEY `dashboardUserId` (`dashboardUserId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
And I have the table that saves what categories the user has saved,
CREATE TABLE IF NOT EXISTS `userMenuTable` (
`menuEntryId` int(11) NOT NULL AUTO_INCREMENT,
`categoryId` int(11) NOT NULL,
`cookieId` varchar(32) NOT NULL,
PRIMARY KEY (`menuEntryId`),
KEY `categoryId` (`categoryId`,`cookieId`),
KEY `cookieId` (`cookieId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6;
The following query should get the categories the user hasn't saved assuming the cookieId stays constant for a user. If it doesn't you should put a userId into the userMenuTable instead. Just replace USERSCOOKIEID with their actual cookie ID.
SELECT * FROM categoryTable WHERE categoryId not in
(SELECT categoryId FROM userMenuTable WHERE cookieId = 'USERSCOOKIEID') as x