I've been looking around but couldn't find my answer anywhere.
I have a MySQL table which looks something like this:
CREATE TABLE IF NOT EXISTS `g_video_watch` (
`vwatch_id` int(11) NOT NULL,
`vwatch_user` int(11) NOT NULL,
`vwatch_track` int(11) NOT NULL,
`vwatch_ip` varchar(255) NOT NULL,
`vwatch_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=36 ;
A page where the user can watch a video inserts everytime a page opens a row with the information from who the user is (vwatch_user) what track/video he or she opens (vwatch_track) and what the IP is. Also the current timestamp is inserted for the goal I'm trying to achieve.
And that goal is to show the tracks/videos which are most watched today. So in other words, select TODAY, GROUP all tracks and check how many rows per group is returned to order in COUNT where views is the highest...
Anybody an idea?
To get 100 most viewed tracks try this:
SELECT vwatch_track, COUNT(*)
FROM g_video_watch
WHERE DATE(vwatch_date) = DATE(NOW())
GROUP BY vwatch_track
ORDER BY COUNT(*) DESC
LIMIT 100
SELECT vwatch_track , count(*)
FROM g_video_watch
WHERE vwatch_date >= CURRENT_DATE
GROUP BY vwatch_track
Related
I'm going crazy trying to get UPDATE to work with a CTE in MySQL.
Here's a simplified schema of sa_general_journal:
CREATE TABLE `sa_general_journal` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Transaction_ID` int(10) unsigned DEFAULT NULL COMMENT 'NULL if not split, same as ID for split records',
`Date` timestamp NOT NULL DEFAULT current_timestamp(),
…
`Statement_s` int(10) unsigned DEFAULT NULL,
…
`Name` varchar(255) DEFAULT NULL,
…
PRIMARY KEY (`ID`),
…
) ENGINE=InnoDB AUTO_INCREMENT=25929 DEFAULT CHARSET=utf8;
Some records are "split," for example, a credit card statement amount might have a sales tax amount that is split out. In such cases, both parts of the split record have the same ID in the Transaction_ID field.
When records are imported in bulk, they can't refer to last_insert_ID in order to fill in the Transaction_ID field, thus the need to go clean these up afterward.
This was my first, naive attempt, which said I had an error near UPDATE. Well duh.
WITH cte AS (
SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
UPDATE cte
SET Transaction_ID = Trans
The CTE itself seems to work, as I can follow it with SELECT * FROM cte and get what I expected.
So I started searching StackOverflow, and discovered that CTEs are not updatable, but that you need to join them to what you want to update. "No problem!" I think, as I code this up:
WITH cte AS (
SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
UPDATE sa_general_journal gj, cte
SET gj.Transaction_ID = cte.Trans
WHERE gj.ID = cte.ID
No joy. Same error message.
My understanding is that in MySQL, you don't need a column list, but I did also try this using the column list (a, b, c), with the proper columns referenced in the UPDATE statement, but it still said I had a problem near UPDATE.
There are incredibly few examples of using UPDATE with WITH on the Internet! I found one, from Percona, which I used to create my attempt above, and then found another very similar example from MySQL itself.
Thanks in advance for any help offered!
CTE is a part of subquery definition, not a part of the whole query. The query must be specified after CTE. CTE cannot be used itself. So
UPDATE sa_general_journal gj
JOIN (WITH cte AS ( SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
SELECT * FROM cte) subquery ON gj.ID = subquery.ID
SET gj.Transaction_ID = subquery.Trans
CTEs work with UPDATE in MySQL 8, but not MariaDB 10.x.
I'm working with a 3rd party MYSQL database over which I have no control except I can read from it. It contains 51 tables with identical column structure but slightly different names. They hold daily summaries for a different data source. Example Table:
CREATE TABLE `archive_day_?????` (
`dateTime` int(11) NOT NULL,
`min` double DEFAULT NULL,
`mintime` int(11) DEFAULT NULL,
`max` double DEFAULT NULL,
`maxtime` int(11) DEFAULT NULL,
`sum` double DEFAULT NULL,
`count` int(11) DEFAULT NULL,
`wsum` double DEFAULT NULL,
`sumtime` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
where ????? changes to indicate the type of data held.
The dateTime field is mirrored across all tables being midnight of every day since the system has been running.
I want to produce a single data set across all tables using an inner join on the dateTime. But to avoid writing
SELECT ad1.maxtime as ad1_maxtime, ad2.maxtime as ad2_maxtime...
51 times for 9 fields is there a way I can bulk create aliases e.g
ad1.* as ad_*, ad2.* as ad_* and so on.
I have looked at Create Aliases In Bulk? but this doesn't seem to work for MySQL. Ultimatly the data is being used by a Django ORM.
EDIT: Unfortunately Union doesn't uniquely identify the fields or group them together e.g.
SELECT * FROM `archive_day_ET` UNION ALL SELECT * FROM `archive_day_inTemp`
results in:
To generate a string with all the field names from those tables, you could query information_schema.columns
For example:
SELECT
GROUP_CONCAT(CONCAT(TABLE_NAME,'.`',column_name,'` AS `',column_name,'_',replace(TABLE_NAME,'archive_day_',''),'`') SEPARATOR ',\r\n')
FROM information_schema.columns
WHERE TABLE_NAME like 'archive_day_%'
A test on db<>fiddle here
And to generate the JOIN's then you could use information_schema.tables
For example:
SELECT CONCAT('FROM (\r\n ',GROUP_CONCAT(CONCAT('SELECT `dateTime` FROM ',TABLE_NAME) SEPARATOR '\r\n UNION\r\n '),'\r\n) AS dt \r\nLEFT JOIN ',
GROUP_CONCAT(CONCAT(TABLE_NAME,' ON ',
TABLE_NAME,'.`dateTime` = dt.`dateTime`') SEPARATOR '\r\nLEFT JOIN ')) as SqlJoins
FROM information_schema.tables
WHERE TABLE_NAME like 'archive_day_%'
A test on db<>fiddle here
For the 2 example tables they would generate
archive_day_ET.`dateTime` AS `dateTime_ET`,
archive_day_ET.`min` AS `min_ET`,
archive_day_ET.`mintime` AS `mintime_ET`,
archive_day_ET.`max` AS `max_ET`,
archive_day_ET.`maxtime` AS `maxtime_ET`,
archive_day_ET.`sum` AS `sum_ET`,
archive_day_ET.`count` AS `count_ET`,
archive_day_ET.`wsum` AS `wsum_ET`,
archive_day_ET.`sumtime` AS `sumtime_ET`,
archive_day_inTemp.`dateTime` AS `dateTime_inTemp`,
archive_day_inTemp.`min` AS `min_inTemp`,
archive_day_inTemp.`mintime` AS `mintime_inTemp`,
archive_day_inTemp.`max` AS `max_inTemp`,
archive_day_inTemp.`maxtime` AS `maxtime_inTemp`,
archive_day_inTemp.`sum` AS `sum_inTemp`,
archive_day_inTemp.`count` AS `count_inTemp`,
archive_day_inTemp.`wsum` AS `wsum_inTemp`,
archive_day_inTemp.`sumtime` AS `sumtime_inTemp`
And
FROM (
SELECT `dateTime` FROM archive_day_ET
UNION
SELECT `dateTime` FROM archive_day_inTemp
) AS dt
LEFT JOIN archive_day_ET ON archive_day_ET.`dateTime` = dt.`dateTime`
LEFT JOIN archive_day_inTemp ON archive_day_inTemp.`dateTime` = dt.`dateTime`
I have 2 tables:
Medical_Appointment
ID INT AUTO_INCREMENT NOT NULL,
Day DATE NOT NULL,
Start_Time TIME NOT NULL,
Patient_ID INT NOT NULL,
Service_ID INT NOT NULL,
PRIMARY KEY(ID)
And
Service
ID INT NOT NULL AUTO_INCREMENT,
Name VARCHAR(30) NOT NULL,
Duration VARCHAR(6) NOT NULL,
PRIMARY KEY(ID)
I want to get the end time of every appointment, and for that I have the next query:
SELECT DATE_FORMAT(m.Day, '%d-%m-%Y') AS `Appointment day:`,
TIME_FORMAT(m.Start_Time, '%H:%i') AS `Appointment start time:`,
ADDTIME(m.Start_Time, TIME_FORMAT(s.Duration, '%H:%i')) AS `Appointment end time:`
FROM Medical_Appointment m
JOIN Service s
ON m.Service_ID = s.ID
WHERE m.Day = '2017-03-14'
ORDER BY m.Start_Time;
This works for me, but it is just a temporary view, I want to stored the result in a column for the Medical_Appointment table because I want to use that value in a Java application and just take it from the database. This is possible?
Alter your table to add the new column.
After that, just insert the result of your select
you would have had end time when updating duration; so you should just also include end time as a field.
P.S. i was unable to comment so writing it as answer
You can check if database 'trigger' can be useful here. Triggers should do the purpose.
You could use a MySQL Table View for that:
CREATE VIEW appointment_info
AS SELECT DATE_FORMAT(m.Day, '%d-%m-%Y') AS `day`,
TIME_FORMAT(m.Start_Time, '%H:%i') AS `start`,
ADDTIME(m.Start_Time, TIME_FORMAT(s.Duration, '%H:%i')) AS `end`
FROM Medical_Appointment m
JOIN Service s
ON m.Service_ID = s.ID;
You could then query the view 'appointment_info' like a usual table e.g.:
SELECT `day` AS `Appointment day:`, `start` AS `Appointment start time:`, `end` AS `Appointment end time:`
FROM appointment_info
WHERE day = '2017-03-14'
ORDER BY `start`;
Of course you could also use Appointment day:, Appointment start time: and Appointment end time: directly as column names in your table view.
I have a MySQL db with a MappingTable which consists of two columns. First column is a date column and another is ID - Autoincrement int column. I created this table for mapping dates and the ID's. When I query the date column with dates to retrieve the ID, no rows are getting selected. Any reason?
I tried
date_format in the SELECT query
str_to_date while checking in the WHERE clause
Compared like current_date > "2016-07-12" AND current_date <= "2016-07-12"
IfI compare LIKE "2016-07-1%" I'm getting matching rows but if I select "2016-07-12%" though there are matching rows, it is giving 0 rows.
I defined my column as DATE only.
Anything I'm missing here?
CREATE TABLE `mapping_table` (
`Current_date` date DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
My question is, I want to select something like this.
select id from mapping_table where current_date="2016-07-12";
I tried with all approaches as mentioned above, but no rows are not retrieving.
use back tick on columns and table names so it wont be read/parse as keyword.
select `id` from `mapping_table` where `current_date` = "2016-07-12";
In the sample you provided you should use a date_format
select id from mapping_table where current_date= DATE_FORMAT("2016-07-12",'%Y-%d-%m') ;
or use a range
select id from mapping_table where current_date
BETWEEN DATE_FORMAT("2016-07-12",'%Y-%d-%m')
and DATE_FORMAT("2016-07-10",'%Y-%d-%m')
I've a table named messages where users of my local hub store their messages(kind of like a web-forums). Currently, a majority of users are participating and I get nearly 30 to 50 new entries to my table everyday.
Since this has been going on for past few years, we've got nearly 100,000 rows of data in table. The table structure is kind of like this. Where fid is the PRIMARY and ip and id(nickname) are just INDEX.
I was using this kind of query uptil now; and then iterating the resultset in luasql as shown in this link. This, according to me, consumes a lot of time and space(in buffers).
`msg` VARCHAR(280) NOT NULL,
`id` VARCHAR(30) NOT NULL,
`ctg` VARCHAR(10) NOT NULL,
`date` DATE NOT NULL COMMENT 'date_format( %m/%d/%y )',
`time` TIME NOT NULL COMMENT 'date_format( %H:%i:%s )',
`fid` BIGINT(20) NOT NULL AUTO_INCREMENT,
`ip` CHAR(39) NOT NULL DEFAULT '127.0.0.1'
My problem is that now-a-days, we've switched to new API of PtokaX and the number of requests to read and write have increased dramatically. Since, I recently read about MySQL procedures, I was thinking if these procedures are a faster or safer way of dealing with this situation.
SELECT *
FROM ( SELECT *
FROM `messages`
ORDER BY `fid` DESC
LIMIT 50 ) AS `temp`
ORDER BY `fid` ASC;
P.S.
We get around one request to read one message every 7 to 10 seconds on average. On weekends, it rises to around one every 3 seconds.
Please let me know if anything more is required.
TO SUM UP
Is their a way that I can call a stored procedure and get the final result in a smaller time. Current query(and method) takes it nearly 3 seconds to fetch and organize the data.
Few things regarding your query:
SELECT *
FROM ( SELECT *
FROM `messages`
ORDER BY `fid` DESC
LIMIT 50 ) AS `temp`
ORDER BY `fid` ASC;
Never SELECT * (all); always specify a column list (what you need)
Subqueries typically cost more (for sorting & storage)
If you are trying to fetch the bottom '50', trying using a BETWEEN clause instead
You can always see what you're query is doing by using EXPLAIN. I would try the following query:
SELECT `msg`, `id`, `ctg`, `date`, `time`, `fid`, `ip` FROM `messages`
WHERE `fid` > (SELECT MAX(`fid`)-50 FROM `messages`)
ORDER BY `fid`