Table INSERT using While loop - sql-server-2008

While I've read many answers here, this is my first question on stackoverflow and I'm reasonably new to SQL. I am trying to use a WHILE loop (SQL Server 2008) to insert some records into a table. Here's the data I'm starting with:
SeasID FacilityID PL Zone Section Row FromSeat ToSeat
11 17 1 g2 cf a 1 5
32 18 14 w13 r2 c 10 12
I need to insert a row for every unique seat into a new table. Here's what I'd like to insert:
SeasID FacilityID PL Zone Section Row Seat
11 17 1 g2 cf a 1
11 17 1 g2 cf a 2
11 17 1 g2 cf a 3
11 17 1 g2 cf a 4
11 17 1 g2 cf a 5
32 18 14 w13 r2 c 10
32 18 14 w13 r2 c 11
32 18 14 w13 r2 c 12
I've tried many things and I don't think I understand loops very well yet. Any help you can provide would be great.

Quick and dirty (Change 1000 to the highest seat number possible. A Persistent Numbers table would help)
;WITH N(Number) AS (SELECT 1 AS Number UNION ALL SELECT Number + 1 FROM N WHERE Number < 1000)
SELECT TheTable.*, N.Number AS Seat
FROM TheTable
INNER JOIN N
ON ToSeat >= N.Number AND FromSeat <= N.Number
ORDER BY N.Number
OPTION(MAXRECURSION 1000)

Related

Query within a query to obtain certain value with multiple joins in MySQL Select

I have 3 tables that I have joined in the MySQL query below. All works well EXCEPT I would like the timeadj value with a 1 in column countingtime
to show from table 'data', not the first timeadj value the query finds.
I know this needs to be a query within a query but I am going around in circles and getting no where.
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(data.timeadj),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC
For example.... In Team 1 (data.teamid=1) there are 8 time values in timeadj. In the adjacent column (countingtime) is a value either 1 or 0 but only ever 1x 1 per team.
Table ttt_entries
ID tttid CoffeeClass
1 23 Mocha
2 52 Espresso
3 6 Frappe
Table ttt_teams
tttid Name
6 Team A
23 Team 1
52 Team 2
Table 'data'
id wtrlid teamid timeadj countingtime division
1 22 23 3467.123 0 10
2 22 23 3467.125 0 20
3 22 23 3467.432 0 10
4 22 23 3469.000 1 10
5 22 23 3469.112 0 10
6 22 23 3468.987 0 5
My code brings back
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3467.123 1 4 1 0 0
I need it to bring back the same data but a different time:
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3469.000 1 4 1 0 0
You can try below way -
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(max(case when countingtime=1 then data.timeadj end)),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC

Retrieve a column with the list of object_id's that occurs together more than once and a second column with the count of how many times it occurs

Note that object_id's 18,10 and 21 are associated to the cart_id 3 once. I wanna know whether the combination occurs again in another cart_id and how many times does that occurs over all the rows existent. I expect two columns as a resultset "combination" and "combination_occurrence_count"
It is quite complicated task to check all possible combinations as it is too many of them.
However, if you simplify your requirements a bit, you can get something useful.
Lets start with finding all combinations of two items. At the beginning you can try the following query:
SELECT
c1.cart_id AS cart1_id
, c1.object_id AS object1_id
, c2.object_id AS object2_id
, cx1.cart_id AS cartX_id
, cx1.object_id AS objectX1_id
, cx2.object_id AS objectX2_id
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
ORDER BY
c1.cart_id
, c1.object_id
, c2.object_id
, cx1.cart_id
, cx1.object_id
, cx2.object_id
There are two ideas behind the query:
Get all possible combinations of two object ids that are exist in
carts. Carts with only one item will be excluded. The only existing
combinations would be analyzed (instead of all possible combinations). [c1 & c2]
Find other carts that have the same object ids combinations [cx1 & cx2]
The results would be something like this:
cart1_id object1_id object2_id cartX_id objectX1_id objectX2_id
3 10 18 30 10 18
3 10 18 31 10 18
3 10 21 30 10 21
3 18 21 30 18 21
30 10 18 31 10 18
Then you can group these results to get "the most popular" pairs:
SELECT
cx1.object_id AS object1_id
, cx2.object_id AS object2_id
, 1 + COUNT(DISTINCT cx1.cart_id) AS cnt
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
GROUP BY
cx1.object_id
, cx2.object_id
ORDER BY
cnt DESC
LIMIT
20
Results:
object1_id object2_id cnt
10 18 3
10 21 2
18 21 2
So pair 10 + 18 is the most popular and are exist in 3 carts.
Pairs 10 + 21 and 18 + 21 are in 2 different carts.
You can continue and do something like this for 3-objects combinations.
P.S. I used the following data set (added a few rows to your data to get a bit more interesting results):
id cart_id object_id
10 2 24
9 3 10
3 3 18
19 3 21
12 4 24
1 7 30
5 9 24
2 11 10
20 14 12
14 14 18
8 14 27
13 15 11
7 16 9
18 16 13
15 20 11
6 21 6
4 23 5
17 23 6
16 25 16
11 29 11
23 30 1
21 30 10
22 30 18
24 30 21
25 31 10
26 31 18
P.P.S. I have not spent too much time on this so it is possible that I missed something in queries. However, I hope you understand the general idea.
The following returns the list of carts with all three objects:
select cart_id
from t
where object_id in (18, 10, 21)
group by cart_id
having count(distinct cart_id) = 3;
select group_concat(`app_item`.`object_id`) as `combination`
from `app_item`
group by `app_item`.`cart_id`
The query return a "combination" resultset as I was looking for:
Since I cannot group again using the "combination" and then make a count of occurrences for each combination and then get the "combination_occurrence_count" it contains, I am now doing this through a method in the application as following
and now I can display an array as key/pair like "combination" => "occurrence count" as following

MySQL select a certain amout of rows for each type in a certain c

I would like to select the first certain number of rows, by groups of a certain column. For example :
Original data:
index type value
0 1 a 0.716430
1 2 a 0.223650
2 3 a 0.375417
3 4 a 0.773874
4 5 a 0.802127
5 6 a 0.956563
6 7 b 0.377718
7 8 b 0.487772
8 9 b 0.672767
9 10 b 0.275895
10 11 b 0.981751
11 12 b 0.914780
12 13 b 0.940582
13 14 c 0.347563
14 15 c 0.101106
15 16 c 0.390205
16 17 c 0.235941
17 18 c 0.593234
18 19 c 0.904659
I would like to select the first 4 rows for each unique value of type, and the order is by index.
So the ideal result would be:
index type value
0 1.0 a 0.716430
1 2.0 a 0.223650
2 3.0 a 0.375417
3 4.0 a 0.773874
4 7.0 b 0.377718
5 8.0 b 0.487772
6 9.0 b 0.672767
7 10.0 b 0.275895
8 14.0 c 0.347563
9 15.0 c 0.101106
10 16.0 c 0.390205
11 17.0 c 0.235941
row_number() is the typical solution to this:
select t.*
from (select t.*,
row_number() over (partition by type order by index) as seqnum
from t
) t
where seqnum <= 4;
In older versions of MySQL, you can do:
select tm.*
from telegram_message tm
where tm.index <= coalesce( (select tm2.index
from telegram_message tm2
where tm2.type = tm.type
order by tm2.index asc
limit 1 offset 3
), tm.index
);
The coalesce() is so all rows are taken if there are not 4 rows for the type.
You can get the result you want by self joining your table on index, where the value of index in the joined table is less than that in the first, and selecting only those rows which have < 4 rows with lower index values:
SELECT t1.id, t1.index, t1.type, t1.value
FROM test t1
LEFT JOIN test t2 ON t2.index < t1.index AND t2.type = t1.type
GROUP BY t1.id, t1.index, t1.type, t1.value
HAVING COUNT(t2.index) < 4
Output:
id index type value
0 1 a 0.71643
1 2 a 0.22365
2 3 a 0.375417
3 4 a 0.773874
6 7 b 0.377718
7 8 b 0.487772
8 9 b 0.672767
9 10 b 0.275895
13 14 c 0.347563
14 15 c 0.101106
15 16 c 0.390205
16 17 c 0.235941
Demo on dbfiddle

mysql join two table rows in one table

I have two tables e_sku and e_availability, In e_sku table i have 45 rows with the default availability as 1, below is an example
id is_available name
1 1 UN001N
2 1 UN002N
3 1 UN003N
4 1 UN004N
5 1 UN005N
6 1 UN006N
7 1 UN007N
8 1 UN008N
9 1 UN009N
10 1 UN010N
11 1 UN011N
12 1 UN012N
13 1 UN013N
14 1 UN014N
15 1 UN015N
16 1 UN016N
17 1 UN017N
18 1 UN018N
19 1 UN019N
20 1 UN020N
21 1 UN021N
22 1 UN022N
23 1 UN023N
24 1 UN024N
25 1 UN025N
26 1 UN026N
27 1 UN027N
28 1 UN028N
29 1 UN029N
30 1 UN030N
31 1 UN031N
32 1 UN032N
33 1 UN033N
34 1 UN034N
35 1 UN035N
36 1 UN036N
37 1 UN037N
38 1 UN038N
39 1 UN039N
40 1 UN040N
41 1 UN041N
42 1 UN042N
43 1 UN043N
44 1 UN044N
45 1 UN045N
Second table is e_availability in this table i am only storing the unavailability with dates below is the example
id e_sku_id is_available working_date
1 5 0 10/20/2016
2 8 0 10/20/2016
3 10 0 10/20/2016
4 1 0 10/20/2016
5 15 0 10/20/2016
6 11 0 10/19/2016
7 1 0 10/19/2016
Because the data is capturing every date for unavailability so i am only gathering the unavailable product's data in e_availability table w.r.t. dates, Now i am looking to show the data for each day as complete skus in such a way that every day report will show 45 skus and for available sku it will show 1 from e_sku table's column is_available and for unavailable sku it will show the column of is_availability from e_availability table
I am using mysql database, I tried many join queries but not getting the report.
can any one guide about which join i require
I got the result by using this query
SELECT * FROM (SELECT id,NAME,1 AS is_available FROM e_sku
WHERE company_id = 2
AND id NOT IN (SELECT id FROM (SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) X)
UNION
SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) Y
ORDER BY id
You can use a LEFT JOIN to detect when a date isn't found in the e_availability table. The join will return NULL for all the columns in that table, then you can default to the value from e_sku.
SELECT d.date, s.id, IFNULL(a.is_available, s.is_available) AS is_available
FROM all_dates AS d
CROSS JOIN e_sku AS s
LEFT JOIN e_availability ON d.working_date = a.date AND s.id = a.e_sku_id
You need to create an additional table all_dates that contains all the dates that you want to report on. See What is the most straightforward way to pad empty dates in sql results (on either mysql or perl end)? for how you can create such a table dynamically.

MySQL count without grouping

I am running the following query to understand to get users' first attempt to answer a question listed next to their second attempt.
SELECT
s.id AS attempt_id_first, m.id AS attempt_id_second, s.user_id
FROM
attempt s
INNER JOIN attempt m on s.user_id = m.user_id
WHERE
s.id<m.id
I end up with this:
attempt_first attempt_second user_id
7 17 1
9 10 2
9 15 2
10 15 2
4 6 9
24 25 15
29 34 19
29 36 19
34 36 19
I would like to have a new column that counts the number of attempts by users so that:
7 17 1 1
9 10 2 3
9 15 2 3
10 15 2 3
4 6 9 1
24 25 15 1
29 34 19 3
29 36 19 3
34 36 19 3
I am sure this is trivial, but I cannot get it to work. Help anyone?
I think this is it: Just display the results, and throw in an extra count subquery:
select
userid,
id,
(select
count('x')
from
attempt x
where
x.userid = a.userid) as attempcount
from
attempt a
If you like to keep the first and second attempt in separate columns, you can of course embed the subselect in your original query.
It seems wrong, though. Firstly, you need to have at least two attemps, otherwise none will show. You can solve that by changing inner join to left join and move the condition in the where clause to that join. Secondly, the 'second attempt' is not the second attempt per say. Actually, for each of the attempts you get all next attempts. Look at the example of user 2. You accidentally get three rows (where there are three attemps), but you get attempt 9 and 10, as well as attempt 9 and 15 as well as 10 and 15. 9, 15 is incorrect, since 15 isn't the attempt that followed 9. The more attempts a user has, the more of these false results you will get.
If you want one attempt listed next to the next one, with the count, I would suggest:
SELECT s.user_id, s.id AS attempt_id_first,
(select s2.id
from attempt s2
where s2.user_id = s.user_id and
s2.id > s.id
order by s2.id
limit 1
) as attempt_id_second,
(select count(*)
from attempt s3
where s3.user_id = s.user_id
) as totalAttempts
FROM attempt s ;
This only lists each attempt once with the next one. The count is included as the last column.