SQL find all records from one table, but only the most recent record from a linked table - sql

I am looking to select all records from my userrecords table and then find the corresponding most recent record from my checkins table.
I need to do this so that I can display whether the user is checked-in or checked-out for the current day and campus.
The outdatetime is a NULL value when the user is currently checked-in, and the query should take into account the current date so that only checkin records for the current date are considered.
My table setup is like so:
CREATE TABLE `userrecords` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(45) NOT NULL,
`surname` varchar(45) NOT NULL,
`email` varchar(45) NOT NULL,
`phone` varchar(15) DEFAULT NULL,
`password` char(64) DEFAULT NULL,
`userlevel` int(1) NOT NULL,
`suspended` varchar(1) DEFAULT NULL,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`lastcheckdate` datetime DEFAULT NULL,
`maincampus` varchar(3) DEFAULT NULL,
`lastlogin` datetime DEFAULT NULL,
`staffid` varchar(6) DEFAULT NULL,
PRIMARY KEY (`userid`),
UNIQUE KEY `email_UNIQUE` (`email`),
UNIQUE KEY `userid_UNIQUE` (`userid`)
) ENGINE=InnoDB AU
CREATE TABLE `checkins` (
`recordid` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) NOT NULL,
`campusid` int(11) NOT NULL,
`indatetime` datetime DEFAULT NULL,
`outdatetime` datetime DEFAULT NULL,
PRIMARY KEY (`recordid`),
KEY `campusid_idx` (`campusid`),
KEY `userid_idx` (`userid`),
CONSTRAINT `campusid` FOREIGN KEY (`campusid`) REFERENCES `campus` (`campusid`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `userid` FOREIGN KEY (`userid`) REFERENCES `userrecords` (`userid`) ON DELETE CASCADE ON UPDATE CASCADE
My query is so far:
SELECT userid,firstname,surname,email,lastcheckdate FROM userrecords WHERE userlevel=0

You can use window functions:
select ur.*, c.*
from userrecords ur left join
(select c.*,
row_number() over (partition by userid order by indatetime desc) as seqnum
from checkins c
) c
on ur.userid = c.userid and ur.seqnum = 1;

Related

How to select all records with foreign key?

I have tables that have been created like so:
CREATE TABLE `d_account` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`account_name` varchar(128) CHARACTER SET utf8 NOT NULL,
`user_id` smallint(5) NOT NULL,
`type_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_account_type` (`type_id`),
CONSTRAINT `FK_type` FOREIGN KEY (`type_id`) REFERENCES `d_types` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);
CREATE TABLE `d_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`id`)
);
How would I select all records that exist in both tables below using the foreign key where the d_type name equals ‘large’?
That's basically just a JOIN like this:
SELECT * FROM d_types t
JOIN d_account a ON t.id = a.type_id
WHERE t.name = 'large';
The * after select should be replaced by the columns you want to select.

SQL query for getting subscription dates

I have these tables into which I would like to check user subscription period:
Entities:
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`city` varchar(30) DEFAULT NULL,
`CONTENT` text DEFAULT NULL,
`country` varchar(50) DEFAULT NULL,
`created_at` datetime(6) DEFAULT NULL,
`discount` decimal(8,2) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`first_name` varchar(50) DEFAULT NULL,
`grand_total` decimal(8,2) DEFAULT NULL,
`item_discount` decimal(8,2) DEFAULT NULL,
`last_name` varchar(50) DEFAULT NULL,
`line1` varchar(50) DEFAULT NULL,
`line2` varchar(50) DEFAULT NULL,
`middle_name` varchar(50) DEFAULT NULL,
`mobile` varchar(15) DEFAULT NULL,
`promo` varchar(100) DEFAULT NULL,
`province` varchar(50) DEFAULT NULL,
`session_id` int(11) DEFAULT NULL,
`shipping` decimal(8,2) DEFAULT NULL,
`status` varchar(100) DEFAULT NULL,
`sub_total` decimal(8,2) DEFAULT NULL,
`tax` decimal(8,2) DEFAULT NULL,
`token` varchar(100) DEFAULT NULL,
`total` decimal(8,2) DEFAULT NULL,
`updated_at` datetime(6) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`phone` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=latin1
CREATE TABLE `subscription` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` decimal(19,2) DEFAULT NULL,
`created_at` datetime(6) DEFAULT NULL,
`currency` varchar(20) DEFAULT NULL,
`duration` bigint(20) DEFAULT NULL,
`end_at` datetime(6) DEFAULT NULL,
`error` varchar(200) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`product` varchar(20) DEFAULT NULL,
`run_at` datetime(6) DEFAULT NULL,
`start_at` datetime(6) DEFAULT NULL,
`status` varchar(20) DEFAULT NULL,
`updated_at` datetime(6) DEFAULT NULL,
`title` varchar(20) DEFAULT NULL,
`parent_transaction_id` int(11) DEFAULT NULL,
`parent_transactionId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23443556 DEFAULT CHARSET=latin1
CREATE TABLE `payment_transactions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` decimal(19,2) DEFAULT NULL,
`code` varchar(100) DEFAULT NULL,
`CONTENT` text DEFAULT NULL,
`created_at` datetime(6) DEFAULT NULL,
`currency` varchar(20) DEFAULT NULL,
`error` varchar(200) DEFAULT NULL,
`external_id` varchar(255) DEFAULT NULL,
`gateway` varchar(20) DEFAULT NULL,
`mode` int(11) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`reconciled_at` datetime(6) DEFAULT NULL,
`reference_transaction_id` int(11) DEFAULT NULL,
`status` varchar(20) DEFAULT NULL,
`type` varchar(20) DEFAULT NULL,
`unique_transactionId` varchar(50) DEFAULT NULL,
`updated_at` datetime(6) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`unique_transaction_id` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=latin1
I'm new to database table design so I need to ask what table relations relations should I use to get the user subscription period using user id?
Is it a good idea to use Orders table as a main table and make SQL queries with JOIN to get the subscription period using user id?
JSFFiddle: http://sqlfiddle.com/#!9/262df6/1
As per your requirement, you need to get the user subscription period using user id.
You can get user subscription period and other data from SUBSCRIPTION table by joining ORDERS table, as they have order_id you can directly join the two tables by querying for user_id in where condition.
select subs.* from subscription subs
left join orders odr on odr.id = subs.order_id
where odr.user_id = 221 -- pass the required user id
specify the required columns and query for the userid in where condition
verified with JSFiddle you shared by adding a record in subscription table : http://sqlfiddle.com/#!9/b834fc/2
The main thing to consider here is how you'll normally be wanting to access these tables in the future. Based on what you've posted, I'm going to assume there are users (I don't see a users table), and that they place orders and also have subscriptions.
The thing these share in common - the relation between the two - is the user. Having the user be the focal point also creates a 1-to-many relationship, as opposed to a many-to-many relationship, which is much easier to manage. So, rather than having orders tied to subscriptions, which could get confusing, I would recommend having them both tied to the user. What if a single user has multiple orders, and multiple subscriptions? Which order would you relate to which subscription?
If you have a users table, then I would structure it so each user gets their own unique primary key. Let's call it user_id. Then, have the user_id in both the subscriptions (relating the subscriptions back to the user) and also the orders (relating orders back to the user).
With the user_id relating the two, you could relate the orders and subscriptions easily.

Cannot add or update a child row: a foreign key constraint fails (Clubs and Users)

User Table
CREATE TABLE IF NOT EXISTS `users` (
`userId` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`firstname` varchar(25) NOT NULL,
`lastname` varchar(25) NOT NULL,
`email` varchar(50) NOT NULL,
`password` varchar(32) NOT NULL,
`addressLine1` varchar(80) NOT NULL,
`addressLine2` varchar(80) NOT NULL,
`town` varchar(30) NOT NULL,
`county` varchar(30) NOT NULL,
PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=55 ;
Club Table
CREATE TABLE IF NOT EXISTS `clubs` (
`clubId` int(11) NOT NULL AUTO_INCREMENT,
`clubName` varchar(100) NOT NULL,
`startTime` varchar(5) NOT NULL,
`finishTime` varchar(5) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`clubId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
memberid Table
CREATE TABLE IF NOT EXISTS `membersid` (
`memberId` int(11) NOT NULL AUTO_INCREMENT,
`clubId` int(11) NOT NULL,
`userId` int(11) NOT NULL,
PRIMARY KEY (`memberId`,`clubId`,`userId`),
UNIQUE KEY `memberId` (`memberId`),
KEY `clubId` (`clubId`),
KEY `userId` (`userId`),
KEY `clubId_2` (`clubId`),
KEY `clubId_3` (`clubId`),
KEY `userId_2` (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
DAO
String query = "INSERT INTO membersid( userId, clubId ) VALUES ( ?,? )";
Keep getting error Cannot add or update a child row: a foreign key constraint fails
If someone could be that would be great:)
Your keys in the membersid table (please change that name to members) are messed up. Try
CREATE TABLE IF NOT EXISTS members
(
`memberId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`clubId` int(11) NOT NULL,
`userId` int(11) NOT NULL,
UNIQUE KEY (`clubId`,`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

SQL delete based on query

How do I delete all laptops made by a manufacturer that doesn’t make PCs?
I currently have the following tables:
CREATE TABLE `Device` (
`model` varchar(50) NOT NULL DEFAULT '',
`speed` double DEFAULT NULL,
`RAM` int(11) DEFAULT NULL,
`HD` int(11) DEFAULT NULL,
`list_price` double DEFAULT NULL,
`type` varchar(45) NOT NULL,
`screen` varchar(45) DEFAULT NULL,
PRIMARY KEY (`model`,`type`)
);
INSERT INTO `Device` VALUES
('GATE TOP',2.5,2000,500,1000,'LAPTOP','12'),
('GATE TOWER',2.5,2000,500,1000,'DESKTOP',NULL),
('HELLO TOWER',3.5,8000,1000,1299,'DESKTOP',NULL),
('MACBOOK AIR',2.5,2048,500,599,'LAPTOP','11'),
('MACBOOK PRO',3.5,8000,1000,1299,'LAPTOP','19'),
('PAAP',2.5,2048,500,599,'DESKTOP',NULL),
('TOWER',3,3100,400,2499,'DESKTOP',NULL),
('ULTRA TOWER',6,5000,1000,8999,'DESKTOP',NULL),
('VAIO',2.5,2000,500,569,'LAPTOP','12'),
('VAIO TOWER',2.5,2000,500,569,'DESKTOP',NULL);
CREATE TABLE `Product` (
`manu_Name` varchar(50) NOT NULL DEFAULT '',
`model` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`manu_Name`,`model`),
KEY `Product` (`model`),
CONSTRAINT `Product_ibfk_1` FOREIGN KEY (`manu_Name`)
REFERENCES `Manufacturer` (`name`),
CONSTRAINT `Product_ibfk_2` FOREIGN KEY (`model`)
REFERENCES `Device` (`model`)
);
INSERT INTO `Product` VALUES
('GATEWAY','GATE TOP'),('GATEWAY','GATE TOWER'),
('ACER','HELLO TOWER'),('APPLE','MACBOOK AIR'),
('APPLE','MACBOOK PRO'),('ACER','PAAP'),
('DELL','TOWER'),('SONY','VAIO'),
('SONY','VAIO TOWER');
CREATE TABLE `Manufacturer` (
`name` varchar(50) NOT NULL,
`country` varchar(50) DEFAULT NULL,
`phone` varchar(10) DEFAULT NULL,
PRIMARY KEY (`name`)
);
INSERT INTO `Manufacturer` VALUES
('ACER','TAIWAN','9024801111'),
('APPLE','UNITED STATES','9028189125'),
('DELL','UNITED STATES','9025551234'),
('GATEWAY','UNITED STATES','8705551698'),
('SONY','JAPAN','0123456789'),
('TOSHIBA','JAPAN','1235553560');
The delete statement would be something like this:
delete from `Device` where `model` in (
select `model` from `Product` where `manu_Name` in ('APPLE')
);

How to use subqueries in MySQL

I have two tables.
Table user:
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int(20) NOT NULL AUTO_INCREMENT,
`ud_id` varchar(50) NOT NULL,
`name` text NOT NULL,
`password` text NOT NULL,
`email` varchar(200) NOT NULL,
`image` varchar(150) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB
and mycatch:
CREATE TABLE IF NOT EXISTS `mycatch` (
`catch_id` int(11) NOT NULL AUTO_INCREMENT,
`catch_name` text NOT NULL,
`catch_details` text NOT NULL,
`longitude` float(10,6) NOT NULL,
`latitude` float(10,6) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`image` varchar(150) NOT NULL,
`user_id` int(20) NOT NULL,
PRIMARY KEY (`catch_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB;
ALTER TABLE `mycatch`
ADD CONSTRAINT `mycatch_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
My goal is: I want to retrieve longitude and latitude from mycatch against given ud_id (from user) and catch_id (from mycatch) where ud_id = given ud_id and catch_id > given catch_id.
I used the query but fail to retrieve
SELECT ud_id=$ud_id FROM user
WHERE user_id =
(
SELECT user_id,longitude,latitude from mycatch
WHERE catch_id>'$catch_id'
)
The error is:
#1241 - Operand should contain 1 column(s)
First, try not to use subqueries at all, they're very slow in MySQL.
Second, a subquery wouldn't even help here. This is a regular join (no, Mr Singh, not an inner join):
SELECT ud_id FROM user, mycatch
WHERE catch_id>'$catch_id'
AND user.user_id = mycatch.user_id
Select m.longitude,m.latitude from user u left join mycatch m
on u.user_id =m.user_id
where u.ud_id=$ud_id and
m.catch_id >$catch_id