select from multiple tables but ordering by a datetime field - mysql

I have 3 tables that are unrelated (related that each contains data for a different social network). Each has a datetime field dated- I'm already grouping by hour as you can see below (this one below for linked_in)
SELECT count(*), date_format(dated, '%Y:%m:%d %H') as hour
FROM upd8r_linked_in_accts
WHERE CAST(dated AS DATE) = '".$start_date."'
GROUP BY hour
I would like to know how to do a total across all 3 networks- the tables for the three are
CREATE TABLE IF NOT EXISTS `upd8r_facebook_accts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_id` varchar(50) NOT NULL,
`user_id` int(11) NOT NULL,
`fb_id` bigint(30) NOT NULL,
`dated` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=80 ;
CREATE TABLE IF NOT EXISTS `upd8r_linked_in_accts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_id` varchar(50) NOT NULL,
`user_id` int(11) NOT NULL,
`linked_in` varchar(200) NOT NULL,
`oauth_secret` varchar(100) NOT NULL,
`first_count` int(11) NOT NULL,
`second_count` int(11) NOT NULL,
`dated` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=200 ;
CREATE TABLE IF NOT EXISTS `upd8r_twitter_accts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_id` varchar(50) NOT NULL,
`user_id` int(11) NOT NULL,
`twitter` varchar(200) NOT NULL,
`twitter_secret` varchar(100) NOT NULL,
`dated` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
something like this ?
(SELECT count(*), date_format(dated, '%Y:%m:%d %H') as hour
FROM upd8r_linked_in_accts
WHERE CAST(dated AS DATE) = '".$start_date."')
UNION ALL
(SELECT count(*), date_format(dated, '%Y:%m:%d %H') as hour
FROM upd8r_facebook_accts
WHERE CAST(dated AS DATE) = '".$start_date."')
UNION ALL
(SELECT count(*), date_format(dated, '%Y:%m:%d %H') as hour
FROM upd8r_twitter_accts
WHERE CAST(dated AS DATE) = '".$start_date."')
UNION ALL
GROUP BY hour
update
the data in the actual database is not related by any pk or fk but the data is related that each table represents a user registering for a social network through the application and therefore i need to show the amount of users registered per hour across all three tables
update 2
the output of the query should show %Y:%m:%d %H and the amount of users registered (records created) that hour across the three tables.. each hour returning a new row (ordered by the time)

You are close to the solution
select t1.hourx, sum(t1.column1)
from (
(
SELECT count(*) as column1, date_format(dated, '%Y:%m:%d %H') as hourx
FROM upd8r_linked_in_accts
WHERE CAST(dated AS DATE) = '".$start_date."'
GROUP BY hourx
)
UNION ALL
(
SELECT count(*) as column1, date_format(dated, '%Y:%m:%d %H') as hourx
FROM upd8r_facebook_accts
WHERE CAST(dated AS DATE) = '".$start_date."'
GROUP BY hourx
)
UNION ALL
(
SELECT count(*) as column1, date_format(dated, '%Y:%m:%d %H') as hourx
FROM upd8r_twitter_accts
WHERE CAST(dated AS DATE) = '".$start_date."'
GROUP BY hourx
)
) t1
GROUP BY t1.hourx
I use 'hourx' to avoid reserve words, maybe not necessary.
I hope this works.
[ADD] This solution is called 'inline view'. You can google for that. It is supported by most of databases (mysql, oracle mssql and etc)

Related

Convert HOUR format into Day-Hour-Minute-Second in mysql

I am using this code am getting output in hours
with the below code.
Import script
CREATE TABLE `customerevent` ( `id` int NOT NULL, `Createddate` datetime DEFAULT NULL, `Modifiedate` datetime DEFAULT NULL, PRIMARY KEY (`id`) );
INSERT INTO customerevent (id, Createddate, Modifiedate) VALUES ('3', '2020-01-08 12:00:00', '2020-01-10 11:30:00');
CREATE TABLE holidays (
Id int NOT NULL AUTO_INCREMENT,
Holiday datetime DEFAULT NULL,
Account_of varchar(45) DEFAULT NULL,
PRIMARY KEY (Id));
My code :
SELECT d.Id, d.Createddate, d.Modifiedate,
SUM((TIMESTAMPDIFF(day, start_date, end_date) -
COALESCE((SELECT COUNT(*) FROM holidays WHERE holiday BETWEEN Createddate AND Modifiedate), 0))* 8 +
TIMESTAMPDIFF(minute, TIME(start_time), TIME(end_time)) / 60) task_time
FROM customerevent d
JOIN ( SELECT Id, DATE(Createddate) start_date, DATE(Modifiedate) end_date
, GREATEST('10:00:00', LEAST('18:00:00', TIME(Createddate))) start_time
, GREATEST('10:00:00', LEAST('18:00:00', TIME(Modifiedate))) end_time
FROM customerevent) dd ON dd.Id = d.Id GROUP BY d.Id;
present output:15.500
Expected output: 15H 30M
we have only 8 working hours per day so it is 15.500
Try This out
CREATE TABLE
customerevent (
id int NOT NULL,
Createddate CURRENT_TIMESTAMP() NULL,
Modifiedate CURRENT_TIMESTAMP()) NULL, PRIMARY KEY (id)
)

SQL - Find Available Slots Within Date Range

I have following database schema:
CREATE TABLE `property` (
`id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL
);
CREATE TABLE `venue` (
`id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`property_id` INT(11) NOT NULL,
`name` VARCHAR(100) NOT NULL
);
CREATE TABLE `venue_available` (
`id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`venue_id` INT(100) NOT NULL,
`day` VARCHAR(10) NOT NULL,
`from_time` TIME NOT NULL,
`to_time` TIME NOT NULL,
`lead_time_in_minutes` INT(11)
);
CREATE TABLE `venue_unavailable` (
`id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`venue_id` INT(100) NOT NULL,
`from_datetime` DATETIME NOT NULL,
`to_datetime` DATETIME NOT NULL
);
CREATE TABLE `venue_reservation` (
`id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`venue_id` INT(100) NOT NULL,
`start_datetime` DATETIME NOT NULL,
`end_datetime` DATETIME NOT NULL
);
I want to find properties having venues available from 25th Aug(Sat) to 27th August (Mon) from 10am to 3pm
Here is the SQL query I tried
SELECT
p.id,
p.name AS property_name,
v.name AS venue_name
FROM
venue v
LEFT JOIN
property p ON v.property_id = p.id
-- venue_available
LEFT JOIN
venue_available va_0 ON va_0.venue_id = v.id
LEFT JOIN
venue_available va_1 ON va_1.venue_id = v.id
WHERE 1 = 1
-- venue_available
AND (
(va_0.day = 'sat' AND va_0.from_time <= '2018-08-25 10:00:00' AND va_0.to_time >= '2018-08-25 15:00:00') AND
(va_1.day = 'sun' AND va_1.from_time <= '2018-08-26 10:00:00' AND va_1.to_time >= '2018-08-26 15:00:00')
)
-- venue_unavailable
AND NOT EXISTS (SELECT * FROM venue_unavailable vu WHERE '2018-08-25 10:00:00' <= vu.to_datetime AND '2018-08-26 15:00:00' >= vu.from_datetime)
GROUP BY
p.id;
The problem with the current query is, the condition for venue_available in SQL query seems to work correctly, but when I add the condition for venue_unavailable it returns me the empty result, however based on the data I am expecting 1 result.
Here is the link to SQL fiddle, if you want to play around with schema and fixtures
http://sqlfiddle.com/#!9/33d60f/10
Here is what I am trying to do
1. Get the list of all properties (not venues)
2. List the property only if one or more venue is available after checking with
venue_available
venue_unavailable
venue_reservation
Can you help me with how to go about this?x
Thank you.
UPDATE1
I followed the following post to determine overlapping dates in venue_unavailable Select rows that are not between dates (reservation)
Alright, so the way I solved it is using sub query which is working now.
I am now using the WHERE clause with something like this
WHERE v.id NOT IN (SELECT venue_id FROM provider_block pb WHERE :start_datetime <= pb.to_date AND :end_datetime >= pb.from_date)
This seems to do the job for now.

Mysql : select aggregated values in between dates

I've got mysql query (generated by zf2), it looks like
SELECT `subt`.`from` AS `from`, SUM(ordered) AS `sum_ordered`,
SUM(income) AS `sum_income`, SUM(sales_by_payment) AS
`sum_sales_by_payment`
FROM (
SELECT `w`.`brand` AS `brand`, `w`.`article` AS `article`,
`w`.`subject` AS `subject`, `w`.`size` AS `size`, `w`.`from` AS
`from`, (
SELECT SUM(IFNULL(income,0)) AS `income`) AS `income`, (
SELECT SUM(IFNULL(income_sum_price,0)) AS `income_sum_price`) AS
`income_sum_price`, (
SELECT SUM(IFNULL(ordered,0)) AS `ordered`) AS `ordered`, (
SELECT SUM(IFNULL(ordered_sum_price,0)) AS `ordered_sum_price`) AS
`ordered_sum_price`, (
SELECT SUM(IFNULL(ordered_max_by_day,0)) AS `ordered_max_by_day`) AS
`ordered_max_by_day`, (
SELECT SUM(IFNULL(return_before_payment,0)) AS
`return_before_payment`) AS `return_before_payment`, (
SELECT SUM(IFNULL(return_before_payment_sum_price,0)) AS
`return_before_payment_sum_price`) AS
`return_before_payment_sum_price`, (
SELECT SUM(IFNULL(sales_by_payment,0)) AS `sales_by_payment`) AS
`sales_by_payment`, (
SELECT SUM(IFNULL(sales_by_payment_sum_price,0)) AS
`sales_by_payment_sum_price`) AS `sales_by_payment_sum_price`, (
SELECT SUM(IFNULL(`return`,0)) AS ```return```) AS `return`, (
SELECT SUM(IFNULL(`return_sum_price`,0)) AS ```return_sum_price```)
AS `return_sum_price`, (
SELECT SUM(IFNULL(`stock`,0)) AS ```stock```) AS `stock`, (
SELECT SUM(IF (sales_by_payment IS NOT NULL,
sales_by_payment_sum_price / sales_by_payment, NULL)) AS
`sale_price`) AS `sale_price`, (
SELECT SUM(income_sum_price * 0.62) AS `our_percent`) AS
`our_percent`, (
SELECT SUM(IFNULL(income_sum_price,0) * 0.25) AS
`cost_price_income`) AS `cost_price_select`, (
SELECT SUM(IFNULL(sales_by_payment_sum_price,0) -
(IFNULL(income_sum_price,0) * 0.25)) AS `profit`) AS `profit`, (
SELECT SUM(IF(income IS NOT NULL, (sales_by_payment / income) *
100, 0)) AS `sales_from_income`) AS `sales_from_income`, (
SELECT (SUM(sales_by_payment) / SUM(return_before_payment)) * 100 AS
`returns_buyout`) AS `returns_buyout`, (
SELECT SUM(return_before_payment) / SUM(ordered) * 100 AS `returns`) AS
`returns`, (
SELECT SUM(sales_by_payment) / SUM(ordered) * 100 AS `buyout`) AS
`buyout`, (
SELECT SUM(IFNULL(income,0) - IFNULL(sales_by_payment,0) +
IFNULL(`return`,0)) AS `total`) AS `total`, (
SELECT (SUM(IFNULL(income,0)) - SUM(IFNULL(stock,0)) -
SUM(IFNULL(`sales_by_payment`,0)) + SUM(IFNULL(`return`,0))) AS
`in_the_way`) AS `in_the_way`
FROM `wildberries` AS `w`
WHERE `from` >= '2016-02-01' AND `end` <= '2017-05-04'
GROUP BY `article`
ORDER BY `article` DESC
LIMIT 20 OFFSET 0) AS `subt`
GROUP BY DAY(`from`)
ORDER BY `from` ASC
If dates range are between one year, all works fine. But if i use different years, it returns only one row.
Could anyone give me advice - why is it happen and how should i modify query?
Table scheme is
CREATE TABLE `wildberries` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`brand` VARCHAR(50) NULL DEFAULT NULL,
`subject` VARCHAR(50) NULL DEFAULT NULL,
`article` VARCHAR(50) NULL DEFAULT NULL,
`size` VARCHAR(50) NULL DEFAULT NULL,
`income` VARCHAR(50) NULL DEFAULT NULL,
`income_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`ordered` VARCHAR(50) NULL DEFAULT NULL,
`ordered_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`ordered_max_by_day` VARCHAR(50) NULL DEFAULT NULL,
`return_before_payment` VARCHAR(50) NULL DEFAULT NULL,
`return_before_payment_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`sales_by_payment` VARCHAR(50) NULL DEFAULT NULL,
`sales_by_payment_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`return` VARCHAR(50) NULL DEFAULT NULL,
`return_sum_price` VARCHAR(50) NULL DEFAULT NULL,
`stock` VARCHAR(50) NULL DEFAULT NULL,
`source_file` VARCHAR(50) NULL DEFAULT NULL,
`from` DATE NULL DEFAULT NULL,
`end` DATE NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `article` (`article`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
In your subquery you group by column article, but you select column from. You don't tell the DBMS which of the article's froms you want to see. This is invalid according to the SQL standard, but MySQL lets this slip and gives you one of the article's froms arbitrarily chosen.
So for the first 20 articles you select rather random dates.
In your main query you group by these dates' days parts. This can result in 1 to 20 rows and is based on coincidence (i.e. how the records happen to be stored on disk at that moment and how the DBMS retrieves them).

MySQL Need advice on Query

I want to fetch latest 3 news from each news type.
CREATE TABLE IF NOT EXISTS `news` (
`news_id` int(8) NOT NULL AUTO_INCREMENT,
`news_heading` tinytext NOT NULL,
`news_description` text NOT NULL,
`news_date` date DEFAULT NOT NULL,
`news_type` tinyint(1) NOT NULL COMMENT '0- PEP|1 - MEDIA|2 - CONSULTING',
`created_date` datetime NOT NULL,
`modified_date` datetime NULL,
`display` tinyint(1) NOT NULL COMMENT '0- ON | 1 -OFF',
PRIMARY KEY (`news_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
Below Query will give me only 1 latest news from all type. Suggest me how we can achieve for top 3 from each type
SELECT * FROM (
SELECT * FROM `news`
ORDER BY `created_date` DESC
) AS TBL
GROUP BY `news_type`
Try this:
SELECT news_id, news_heading, news_description, news_date,
news_type, created_date, modified_date, display
FROM (SELECT news_id, news_heading, news_description, news_date,
news_type, created_date, modified_date, display,
IF(#news_type = #news_type:=news_type, #id:=#id+1, #id:=1) AS id
FROM news, (SELECT #id:=1, #news_type:=0) A
ORDER BY news_type, created_date DESC
) AS A
WHERE id <= 3;

SELECT with WHERE IN and subquery extremely slow

I want to exectute the following query:
SELECT *
FROM `bm_tracking`
WHERE `oid` IN
(SELECT `oid`
FROM `bm_tracking`
GROUP BY `oid` HAVING COUNT(*) >1)
The subquery:
SELECT `oid`
FROM `bm_tracking`
GROUP BY `oid`
HAVING COUNT( * ) >1
executes in 0.0525 secs
The whole query "stucks" (still processing after 3 minutes...). Column oid is indexed.
Table bm_tracking contains around 64k rows.
What could be the reason for this "stuck"?
[Edit: Upon request]
CREATE TABLE `bm_tracking` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`oid` varchar(10) NOT NULL,
`trk_main` varchar(50) NOT NULL,
`tracking` varchar(50) NOT NULL,
`label` text NOT NULL,
`void` int(11) NOT NULL DEFAULT '0',
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `oid` (`oid`),
KEY `trk_main` (`trk_main`),
KEY `tracking` (`tracking`),
KEY `created` (`created`)
) ENGINE=MyISAM AUTO_INCREMENT=63331 DEFAULT CHARSET=latin1
[Execution Plan]
Generally exists EXISTS faster than IN so you can try this and see if it executes better for you
SELECT *
FROM `bm_tracking` bt
WHERE EXISTS
( SELECT 1
FROM `bm_tracking` bt1
WHERE bt.oid = bt1.oid
GROUP BY `oid`
HAVING COUNT(*) >1
)
EDIT:
if you notice from the EXPLAIN you posted... the IN() is considered as a DEPENDENT SUBQUERY which is a correlated subquery... meaning that for every row in the table all rows in the table are pulled and compared... so for example 1000 rows in the table would mean 1000 * 1000 = 1 million comparisons -- thats why its taking such a long time