My Tables:
CREATE TABLE `binary` (
`binaryid` int(15) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`binaryid`)
);
CREATE TABLE `binarycollection` (
`binaryid` int(10) unsigned NOT NULL,
`collectionid` int(10) unsigned NOT NULL,
UNIQUE KEY `collectionid` (`collectionid`,`binaryid`),
KEY `binaryid` (`binaryid`)
);
In the binary table there can only exist one record to a binaryid.
The binarycollection table ties the binary to multiple collections.
What I need to do is make a query that will select all rows in binary that have exactly 1 relations in binarycollection.
So given the example:
binary:
1
2
3
4
5
6
7
binarycollection:
(binaryid collectionid)
1 1
2 1
3 1
3 2
4 1
4 2
5 2
6 2
It should return binaryids 1, 2, 5, and 6.
Any help is appreciated. :)
ps. This needs to be efficient, the tables contain millions of rows.
Use GROUP BY :
Select binaryid from binarycollection group by binaryid having count(*)=1
It should work out to a simple query since your referential integrity doesn't allow repeat pairs in the binarycollection table:
SELECT binaryid
FROM binarycollection
GROUP BY binaryid
HAVING ( COUNT(binaryid) = 1 )
join it with the original binary table to check for valid reference then group the binaryID
SELECT a.binaryid
FROM `binary` a
INNER JOIN `binarycollection` b
on a.binaryid = b.binaryid
GROUP BY a.binaryid
HAVING COUNT(a.binaryid) = 1
Related
I'm trying to build a recursive query to enable me to find all future sports match records for the two players of a given match. In addition to this I need the query to return any match for any player that plays in any descendant match. To illustrate using some example data:
match_id
match_date
p1_id
p2_id
1
01/01/2022
1
2
2
02/01/2022
1
3
3
03/01/2022
3
4
4
04/01/2022
5
6
I only really need match_id so if the start match is match_id = 1 then I'm looking for the query to return 1. The query should also return 2 because p1_id = 1 played in the start match. The query should also return 3 because p2_id = 3 played in match_id = 2.
I've written the following query:
WITH RECURSIVE match_ids AS (
SELECT
rt1.match_id,
rt1.p1_id,
rt1.p2_id,
rt1.match_date
FROM recursive_test_so AS rt1
WHERE rt1.match_id = 1
UNION ALL
SELECT
rt2.match_id,
rt2.p1_id,
rt2.p2_id,
rt2.match_date
FROM recursive_test_so AS rt2
JOIN match_ids ON
rt2.match_date > match_ids.match_date
WHERE (
rt2.p1_id IN (match_ids.p1_id, match_ids.p2_id)
OR rt2.p2_id IN (match_ids.p1_id, match_ids.p2_id)
)
)
SELECT DISTINCT match_id
FROM match_ids;
This works fine on the sample data.
However, when I scale the data up to 10k rows then the query runs for about 5 mins with no output and then I get the following error:
Error Code: 1030. Got error 1 - 'Operation not permitted' from storage engine
What might I be doing wrong?
SQL to replicate the sample data table:
CREATE TABLE `recursive_test_so` (
`match_id` int NOT NULL,
`match_date` date NOT NULL,
`p1_id` int NOT NULL,
`p2_id` int NOT NULL,
PRIMARY KEY (`match_id`),
KEY `match_date` (`match_date`),
KEY `p1_id` (`p1_id`),
KEY `p2_id` (`p2_id`),
KEY `comp_all` (`match_date`,`p1_id`,`p2_id`),
KEY `comp_player_ids` (`p1_id`,`p2_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci;
INSERT INTO `recursive_test_so`
VALUES
(1,'2022-01-01',1,2),
(2,'2022-01-02',1,3),
(3,'2022-01-03',3,4),
(4,'2022-01-04',5,6);
Not sure how I could post the 10k rows data?
I have questions about different categories, questions about math, about english...
my table questions:
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`cat_id` int(11) UNSIGNED NOT NULL,
`question` text NOT NULL,
KEY `ids` (`id`, `cat_id`),
FOREIGN KEY (`cat_id`) REFERENCES categories (`id`),
PRIMARY KEY (`id`)
So, for example, the user is answering question about math (cat_id = 1), he is in question id 3 (the first one). When he click NEXT I pass the question id to mysql to get next one:
SELECT id, question FROM questions where cat_id = 1 and id > 3 limit 1
With this select I get the next math question (id 5). But if it is the last math question I'd like to go back to the first question (for example no id > 6, go to the id = 3):
1 - 3(english) - can or may?
2 - 2(history) - Who Discovered America?
3 - 1(math) - 1+1 = ?
4 - 3(english) - can or could?
5- 1(math) - 2+2 = ?
6 - 1(math) - 3+3 = ?
7 - 2(history) - When Was the War of 1812?
So how can I go back to the first question of some category if there is not a new one after to select? I'd like to create an infinity loop in questions.
This query should work:
select id, question from (
SELECT id, question FROM questions where cat_id = 1 and id > 3 order by id limit 1
UNION
SELECT id, question FROM questions where cat_id = 1 order by id limit 1
) limit 1
Select one record with id greater than your id and the first of all. So if you get no with id greater your id you shoult get the first one
I have a table:
id timestamp
1 1
23 2
12 4
45 6
3 7
4 8
I need this result:
major minor
1 2
1 4
1 6
2 4
2 6
2 7
I need to join each number, with the next 3 smallest numbers. Since these numbers are inserted out of order, I can't use the ids.
Because the numbers are also not in regular intervals I cannot set a specific limit to find the max number to join with.
Solutions I have:
I could create a temp table and use an auto increment id to do this.
I can do this for a single number, and write a script to iterate through the table. This is the query for it (Going with this for now, till something better comes up):
SELECT * FROM
(SELECT id major_id, timestamp major_timestamp FROM timestamps WHERE interval_id=7 ORDER BY timestamp DESC limit 1) timestamps_major
LEFT JOIN
(SELECT id minor_id, timestamp minor_timestamp FROM timestamps WHERE timestamp < (SELECT timestamp FROM timestamps WHERE interval_id=7 ORDER BY timestamp DESC limit 1) ORDER BY timestamp DESC LIMIT 2) timestamps_minor
ON major_timestamp>minor_timestamp
This just needs to be done for all numbers once, and then once per day to calculate and store a moving average. So speed is not an issue.
Wondering what is the best way to approach this. Thanks.
EDIT:
This is the actual table with timestamps and ids. The example I posted is just simplified for the sake of the question.
CREATE TABLE `timestamps` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`interval_id` tinyint(3) unsigned NOT NULL,
`timestamp` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `interval_timestamp` (`interval_id`,`timestamp`),
KEY `interval_id` (`interval_id`),
KEY `timestamp` (`timestamp`),
CONSTRAINT `timestamps_ibfk_1` FOREIGN KEY (`interval_id`) REFERENCES `intervals` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=75157 DEFAULT CHARSET=latin1
Here's a possible solution (see this sqlfiddle to play around with it)
SELECT *
FROM mytable major inner join mytable minor
ON minor.timestamp > major.timestamp
WHERE (SELECT COUNT(*) FROM mytable m WHERE m.timestamp < minor.timestamp and m.timestamp > major.timestamp) < 3
ORDER BY major.timestamp, minor.timestamp
I'm definitely not confident this is the cleanest solution (and I didn't do anything to handle "ties" for equal timestamps), but it does do what you want so it might be something to build off of at a minimum.
All I am doing is joining the tables then counting the number of rows "between" the major and minor so that I don't get too many.
I got two tables table 1 and 2 as shown below. I need to insert the Std_rid for the row which has A and its corresponding Act_rid present in table 2 in resultant table 3. I'm only using the sample here. I'm very confused whether to use pivot or unpivot here. Any help appreciated. Thanks
Table 1
----------
G_Standard N_Standard Skill One_for_all Am_Water B2Future Std_rid
ELW.6 Lit.W.K.6 Writing A 1
ELW.8 Lit.W.K.8 Writing A 2
ELW.7 Lit.W.K.7 Writing A 3
Table 2
----------
Act_rid Act_Desc date createdby
3 Am_Water 2/4/15 sys
6 B2Future 2/4/15 sys
1 One_for_all 2/14/15 sys
Output Result Table 3
----------
ID Std_rid Act_rid
1 1 3
2 2 6
3 3 1
This is an UNPIVOT. UNPIVOT turns columns into rows.
;WITH Unpivot_Table_1 AS (
SELECT Std_rid,
Act_Desc
FROM [Table 1]
UNPIVOT (Value FOR Act_Desc IN ([One_for_all],[Am_Water],[B2Future])) u
WHERE u.Value = 'X'
)
SELECT ROW_NUMBER() OVER(ORDER BY t1.Std_rid) AS ID,
t1.Std_rid,
t2.Act_rid
FROM Unpivot_Table_1 t1
JOIN [Table 2] t2
ON t2.Act_Desc = t1.Act_Desc;
I hope this is something for data integration. Otherwise, y'all need to shoot whomever designed this.
Test data:
CREATE TABLE dbo.[Table 1]
(
Std_rid INT NOT NULL PRIMARY KEY,
One_for_all VARCHAR(1),
Am_Water VARCHAR(1),
B2Future VARCHAR(1)
);
INSERT INTO dbo.[Table 1] (Std_rid,One_for_all,Am_Water,B2Future)
VALUES
(1,NULL,'X',NULL),
(2,NULL,NULL,'X'),
(3,'X',NULL,NULL);
CREATE TABLE dbo.[Table 2]
(
Act_rid INT NOT NULL PRIMARY KEY,
Act_Desc VARCHAR(30)
);
INSERT INTO dbo.[Table 2] (Act_rid,Act_Desc)
VALUES
(3,'Am_Water'),
(6,'B2Future'),
(1,'One_for_all');
An example to demonstrate the problem:
ID: The primary key.
argID: A foreign key pointing to another table.
dependentID: A foreign key pointing to the field ID of the table itself.
dependentArgID: A foreign key pointing to the same table as argID.
I want to combine two associated rows (having the same dependentID) into one result row respectively, always selecting the date of the first and the number of the next row:
ID argID dependentID dependentArgID date number
1 1 2 2 2016-06-06 null
2 2 2 null null 1
3 1 4 2 2016-06-07 null
4 2 4 null null 2
...
Desired result:
argID date dependentArgID number
1 2016-06-06 2 1
1 2016-06-07 2 2
...
Problem in short form: To rows with the same dependentID should be "merged" into one row with the date and the number (and optionally the argID and the dependentArgID) of these rows.
What I tried, is a self-join, but I do not get the right rows grouped:
NOT working correctly (and without the additional result fields):
SELECT `b`.`date`, `a`.`number`
FROM `table` `a` LEFT JOIN `table` `b` ON `a`.`argID` = `b`.`dependentArgID`
WHERE `a`.`argID` = 2
GROUP BY `a`.`dependentID`;
The first try (see my post) pointed to the right direction.
The correct solution is:
SELECT `b`.`argID`, `b`.`date`, `b`.`dependentArgID`, `a`.`number`
FROM `table` `a`
CROSS JOIN `table` `b`
ON `a`.`ID` = `b`.`dependentID`
WHERE `a`.`argID` = 2 AND `b`.`date` IS NOT NULL
GROUP BY `a`.`dependentID`;
Thanks to all helpers for the brain stimulation.