I am trying to create n duplicates(say 5) of a each record from a table with an increment on the week number associated with each record.
Say there is a table with the following as columns - week, id
and there is a record - 1, John
I want the record for John to repeat 5 times to obtain -
1, John
2, John
3, John
4, John
5, John
Well, you can generate a table with five columns and then use that:
select (t.week + x.inc) as week, t.name
from t cross join
(select 0 as inc union all
select 1 as inc union all
select 2 as inc union all
select 3 as inc union all
select 4 as inc
) x;
Related
I need to assign jobs to users based on a score (number of "chances") calculated from previous jobs they have done. Here's my table of users:
user chances
Anna 6
Barry 4
Steve 3
Jackson 3
Helga 3
Maureen 3
Paul 3
Karen 2
Anita 2
Samson 2
Frank 2
Jean 1
Lilly 1
Boris 1
In another table, I have 100 rows of unassigned jobs (with currently NULL user), e.g.
id title user
1 Sort filing NULL
2 Clean office NULL
3 Order stationery NULL
I want to assign these jobs to the users above using a weighting based on the number of "chances" they have. For example, Anna will have 6 chances to be assigned one of these jobs, while Boris will have 1.
I've been playing around with a CASE which will assign a user to jobs, but nothing is satisfactory.
What's the best way for me to achieve this? Thanks
Presumably, you're after something like this...
SELECT user
FROM my_table
ORDER BY RAND() * chances * (SELECT SUM(chances) FROM my_table) DESC ;
If the changes are a small number and integers, then the easiest way might be:
update anothertable at
set user = (select user
from chances c cross join
(select 1 as n union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
) n
on c.chances <= n.n
where at.user is null
order by rand()
limit 1
);
The where clause is just so MySQL doesn't get the (brilliant) idea of optimizing away the subquery and only calling it once.
So guys, I really do need help with this one:
I have this table:
---------------
mytable
---------------
id col1
1 Winston Churchill
2 Mahatma Ghandi
3 Nnamdi Azikiwe
4 John Kennedy
5 John Paul II
6 Nelson Mandela
7 John Kennedy
8 Mikhail Gorbachev
9 John Kennedy
What I want to do is find rows with duplicated col1 and for each of them, append incremental numbers to the value of col. In the end, we should be left with this:
---------------
mytable
---------------
id col1
1 Winston Churchill
2 Mahatma Ghandi
3 Nnamdi Azikiwe
4 John Kennedy 1
5 John Paul II
6 Nelson Mandela
7 John Kennedy 2
8 Mikhail Gorbachev
9 John Kennedy 3
The problem of the duplicate col1 is only a part of your problem ..
but if you don't want a trigger or a server side procedure you can try the follow query .
You should repeat this command as many times as the maximum number of repetitions ..
From time to time the repetition with the highest id receives a value equal to count, and the next repetition time being the new name is not counted
update my_table as a
inner join (
select col1, count(*) as num, max(id) as id
from my_table
group by col1
having count(*) >1 ) t on a.col1 = t.col1 and a.id = t.1
set a.col1 = concat( a.col1, ' ', t.num )
I have the following table:
table: people
id | name | income
==========================
1 Bob 10
2 John 5
3 Amy 15
4 Alyson 5
5 Henry 20
I want to take the average of only a select number of rows, like this:
SELECT
id,
name,
(AVG(
SELECT income FROM people WHERE FIND_IN_SET(id, '1,2,3')
) - income) AS averageDiff
FROM people;
I expect to get a result like this:
id | name | averageDiff
==========================
1 Bob 0
2 John 5
3 Amy -5
4 Alyson -5
5 Henry 10
However, I get an error (#1064) when trying to use the SELECT clause inside of the AVG function. How can I do this?
Use this syntax:
SELECT avg(income) FROM people WHERE FIND_IN_SET(id, '1,2,3')
You need to enclose the above query in brackeds in this way:
SELECT
......
(ABS(IFNULL(`age`, 0)
- IFNULL((SELECT AVG(age) FROM people WHERE FIND_IN_SET(id, '1,2,3')), 0)))
+ (ABS(IFNULL(`income`, 0)
- IFNULL((SELECT AVG(income) FROM people WHERE FIND_IN_SET(id, '1,2,3')), 0))) AS sumAvg
FROM `people`
....
If you want the average for everybody as your starting point, calculate that with a query and cross join it to the people you want to include:
SELECT
people.id,
people.name,
people.income - av.avgincome AS averageDiff
FROM people
CROSS JOIN (SELECT AVG(income) AS avgincome FROM people) av
WHERE people.ID IN (1, 2, 3)
If you want the average for the subset of people with ID 1, 2 or 3 as your starting point you can do it like this:
SELECT
people.id,
people.name,
people.income - av.avgincome AS averageDiff
FROM people
CROSS JOIN (
SELECT AVG(income) AS avgincome
FROM people
WHERE ID IN (1, 2, 3)) av
WHERE people.ID IN (1, 2, 3)
Both approaches avoid the correlated subquery (meaning a SELECT for a column name based on the top-level table), which is slow with large recordsets.
The FIND_IN_SET(people.id, '1,2,3') will work, but if you have an index ontable.idtheIN (1, 2, 3)` will be much faster. It will probably be faster even if you don't have the index.
First of all, I don't think my title is good, but I couldn't think of a better one. Please feel free to change it.
I have a table that keeps record of a pair of rows.
The following is a sample table structure.
table History
user_id row_1 row_2
2 1 2
2 1 3
table Rows
row_id
1
2
3
4
5
6
I would like to query to get only a pair of rows that are not in the 'History' table.
so..I like to get the following result.
row pairs:
1,4
1,5
1,6
2,3
2,4
2,5
2,6
and so on
Can I do it with one query?
Just added:
I just made a query that works, but I am not sure about the performance.
select r1.row_id, r2.row_id from rows as r1 cross join rows as r2
where r1.row_id!=r2.row_id and ( r1.row_id + r2.row_id) not in (select row_1 + row_2 from history)
order by r1.row_id desc
Would it be super slow?
Something like this. You haven't made the correlations clear between the fields but this should be easy to adapt.
select h.row_id r1, r.row_id r2
from rows h
cross join rows r
left join history h2 on h2.row_1=h.row_id and h2.row_2=r.row_id
where h2.row_1 is null
The CROSS JOIN produces all the possible combinations of row_id x row_id
THE LEFT JOIN attempts to find the combination in the history table
The WHERE clause picks out where the combination is not found
I think this might work:
SELECT DISTINCT
CASE WHEN r1.row_id < r2.row_id THEN r1.row_id ELSE r2.row_id END AS row_id_1,
CASE WHEN r1.row_id < r2.row_id THEN r2.row_id ELSE r1.row_id END AS row_id_2
FROM Rows AS r1
INNER JOIN Rows AS r2 /* ON r1.row_id <> r2.row_id */
WHERE (r1.row_id, r2.row_id) NOT IN (
SELECT row_1, row_2
FROM history
UNION
SELECT row_2, row_1
FROM history
)
ORDER BY 1, 2
Returns:
1, 1
1, 4
1, 5
1, 6
2, 2
2, 3
2, 4
2, 5
2, 6
3, 3
3, 4
3, 5
3, 6
4, 4
4, 5
4, 6
5, 5
5, 6
6, 6
This query will be super slow.
given a users qualification id's how would you find the jobs they can do using SQL?
1) for example a user with only qualification 1 could only do job3
and not 1 and 4 because you need more than one qualification.
2) a user with qualifications 1 and 2 could do jobs 1 and 3 but not 4
JOBDETAILS TABLE
JobID ,QualificationID
1, 1
1, 2
3, 1
4, 1
4, 2
4, 3
thanks for any help
TJ
SELECT DISTINCT JobID
FROM JobDetails
WHERE QualificationID IN (#Quals)
AND JobID NOT IN
(
SELECT DISTINCT JobID
FROM JobDetails
WHERE QualificationID NOT IN (#Quals)
)
(Apologies for syntax issues; I work with SQL Server, not MySQL)