MariaDB / MySQL Combine two tables - mysql

I have 2 tables tnHeaders and tnData
tnHeaders
fnIDX
fnDESCRIPTION
1
h1
2
h2
3
h3
tnData
fnIDX
fnHEADER_IDX
fnDESCRIPTION
1
1
d1
2
1
d2
3
1
d3
4
2
d4
5
2
d5
6
2
d6
7
3
d7
8
3
d8
9
3
d9
and would like to produce this output
fnOUTPUT
h1
d1
d2
d3
h2
d4
d5
d6
h3
d7
d8
d9
I can do this in code no problem, but how can I do this in SQL? (Make the server work)

You need to use UNION ALL for the descriptions of both tables and sort the results in such a way that headers are on top of their data:
SELECT fnOUTPUT
FROM (
SELECT fnDESCRIPTION fnOUTPUT, fnIDX header_index, 1 is_header FROM tnHeaders
UNION ALL
SELECT fnDESCRIPTION, fnHEADER_IDX, 0 FROM tnData
) t
ORDER BY header_index, is_header DESC, fnOUTPUT;
See the demo.

Related

Stored procedure to subtract from column with same dates

I have the following columns:
2022-05-25T17:31:34+0000 92 7 1
2022-05-25T16:06:46+0000 50 5 9
2022-05-25T13:05:27+0000 91 10 106
2022-05-25T09:17:01+0000 48 4 4
2022-05-25T08:43:05+0000 60 4 2
2022-05-25T06:26:38+0000 24 3 6
2022-05-24T15:14:49+0000 55 12 6
2022-05-24T12:25:35+0000 43 8 2
2022-05-24T11:15:24+0000 66 7 2
2022-05-24T10:45:56+0000 37 15 2
2022-05-23T17:51:09+0000 59 7 1
2022-05-23T17:50:44+0000 47 6 3
2022-05-23T15:48:02+0000 126 7 13
2022-05-23T11:42:26+0000 64 9 9
2022-05-27T06:00:29+0000 3 0 1
2022-05-25T17:31:34+0000 96 7 1
2022-05-25T16:06:46+0000 55 5 9
2022-05-25T13:05:27+0000 99 11 116
2022-05-25T09:17:01+0000 52 4 15
2022-05-25T08:43:05+0000 61 4 2
2022-05-25T06:26:38+0000 26 3 6
2022-05-24T15:14:49+0000 57 13 7
2022-05-24T12:25:35+0000 43 8 2
2022-05-24T11:15:24+0000 66 7 2
2022-05-24T10:45:56+0000 38 15 2
2022-05-23T17:51:09+0000 59 7 1
2022-05-23T17:50:44+0000 47 6 3
2022-05-23T15:48:02+0000 127 7 13
If you look at the 16th row it has the same date as the first row but the number of PostLikes are different (92 and 96) PostComments and PostShares also change. I want to create a stored procedure where when I input the date it will return the difference. For example, if I select the third row with date 2022-05-25T13:05:27+0000 it should give the result:
DateT PostLikes PostComments PostShares
2022-05-25T13:05:27+0000 7 1 10
Now one method of doing this is:
select max(PostLikes) - min(PostLikes) as LikeDifference, max(PostComments) - min(PostComments) as CommentDifference, max(PostShares) - min(PostShares) as ShareDifference
from kpitb.userLikes
where DateT = "2022-05-25T17:31:34+0000";
But this method is only good if there are two values, the database is going to have several values with the same dates. (Note DateT is VARCHAR)
For e.g.
Row 1 2022-05-25T13:05:27+0000 24
Row 2 2022-05-25T13:05:27+0000 34
Row 3 2022-05-25T13:05:27+0000 67
How to find the difference.
Any help would be appreciated.
Using window functions you can find the max id and the previous values and the main query becomes trivial.
with cte as
(select t.*,
lag(postlikes) over(partition by datet order by id) prevlikes,
lag(postcomments) over(partition by datet order by id) prevcomments,
lag(postshares) over(partition by datet order by id) prevshares,
t1.maxid
from t
join (select max(id) maxid,datet from t group by datet) t1 on t1.datet = t.datet
order by datet,id
)
select datet,
case when prevlikes is null then postlikes else postlikes - prevlikes end likes,
case when prevcomments is null then postcomments else postcomments - prevcomments end comments,
case when prevshares is null then postshares else postshares - prevshares end shares
from cte
where id = maxid;
https://dev.mysql.com/doc/refman/8.0/en/window-functions.html

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

Update/Delete using views in parent tables

I have a table A with columns c1,c2,c3 and c4. I have another table B with the same columns(c1,c2,c3,c4).
The contents of both the tables are almost same. The only difference is that the table A contains some duplicate rows since no unique index in A.
I have a view C joining A and B. How can I find the rows that are updated/deleted in A, so that the same can be updated/deleted from B as well, using view C.
Here is sample data.
A
c1 c2 c3 c4
1 2 3 4
1 2 3 4
1 3 3 4
2 5 6 7
B
c1 c2 c3 c4
1 2 3 4
1 3 3 4
2 5 6 7
So, B= A - (duplicate entries)
In B, (c1,c2) is the unique key.
I have a view C with joins to A and B.
Goal : If a row is deleted from A, say (1,3,3,4), the same row should be deleted from B also.
Question : How can I use the view C to achieve the above mentioned Goal

Get Hierarchial Data using LINQ

ID Name Designation PID
1 E1 D1 0
2 E2 D2 0
3 E3 D3 1
4 E4 D3 1
5 E5 D4 3
6 E6 D4 3
7 E7 D4 2
8 E8 D4 2
How can we get all the child employees based on the parent employee using LINQ ?
For eg., if we want child records for employee E1 we should get E3,E4,E5,E6
Thanks in advance...
You can't do it using one single LINQ query. But you can do it using a recursive function smth like:
IList<Employee> GetAllChildren(IList<Employee> employees, int pid)
{
var children = employees.Where (e => e.PID == pid).ToList();
children.AddRange (children.SelectMany (e => GetAllChildren (employees, e.ID)).ToList());
return children;
}

Improvement of VBA code in Access to do something like a pivot table

I have a table of data in MS Access 2007. There are 6 fields per record, thousands of records. I want to make a sort of pivot table like object. That is, if any two rows happens to be the same in the first 4 fields, then they will end up grouped together into one row. The column headers in this pivot table will be the values from the 5th field, and the value in the pivot table will be the 6th field, a dollar amount. Think of the 5th field as letters A, B, C, D, E, F, G. So, the table I start with might have a row with A in the 5th field and $3.48 in the 6th field. Another row may match in the first 4 fields, have B in the 5th field and $8.59 in the 6th field. Another may match in the first 4 fields, have E in the 5th field and $45.20 in the 6th field. I want all these rows to be turned into one row (in a new table) that starts with the first 4 fields where they match, then lists $3.48, $8.59, $0.00, $0.00, $45.20, $0.00, $0.00, corresponding to column headers A, B, C, D, E, F, G (since no records contained C, D, F, G, their corresponding values are $0.00), and then ends with one more field that totals up the money in that row.
Currently, I have some VBA code that does this, written by someone else a few years ago. It is extremely slow and I am hoping for a better way. I asked a previous question (but not very clearly so I was advised to create a new question), where I was asking if there was a better way to do this in VBA. My question asked about reading and writing large amounts of data all at once in Access through VBA, which I know is a good practice in Excel. That is, I was hoping to take my original table and just assign the entire thing to an array all at once (as in Excel, instead of cell by cell), then work with that array in VBA and create some new array and then write that entire array all at once to a new table (instead of record by record, field by field). From the answers in that question, it seems like that is not really a possibility in Access, but my best bet might be to use some sort of query. I tried the Query Wizard and found the Cross Tab query which is close to what I describe above. But, there appears to be a max of 3 fields used in the Row Heading, whereas here I have 4. And, instead of putting $0.00 when a value is not specified (like C, D, F, G in my example above), it just leaves a blank.
Update (in response to Remou's comment to give sample data): Here is some sample data.
ID a b c d e f
7 1 2 3 5 A 5
8 1 2 3 5 B 10
9 1 2 3 5 C 15
10 1 2 3 5 D 20
11 1 2 3 5 E 25
12 1 2 4 4 A 16
13 1 2 4 4 B 26
14 1 3 3 7 D 11
15 1 3 3 7 B 11
The result should be:
a b c d an bn cn dn en Total
1 2 3 5 5 10 15 20 25 75
1 2 4 4 16 26 0 0 0 42
1 3 3 7 0 11 0 11 0 22
But, when I copy and paste the SQL given by Remou, the only output I get is
a b c d an bn cn dn en
1 2 3 5 5 10 15 20 25
This is, I think, what you want, but it would be better to consider database design, because this is a spreadsheet-like solution.
SELECT t0.a,
t0.b,
t0.c,
t0.d,
Iif(Isnull([a1]), 0, [a1]) AS an,
Iif(Isnull([b1]), 0, [b1]) AS bn,
Iif(Isnull([c1]), 0, [c1]) AS cn,
Iif(Isnull([d1]), 0, [d1]) AS dn,
Iif(Isnull([e1]), 0, [e1]) AS en
FROM (((((SELECT DISTINCT t.a,
t.b,
t.c,
t.d
FROM table3 t) AS t0
LEFT JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS a1
FROM table3 t
WHERE t.e = "A") AS a0
ON ( t0.d = a0.d )
AND ( t0.c = a0.c )
AND ( t0.b = a0.b )
AND ( t0.a = a0.a ))
LEFT JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS b1
FROM table3 t
WHERE t.e = "B") AS b0
ON ( t0.d = b0.d )
AND ( t0.c = b0.c )
AND ( t0.b = b0.b )
AND ( t0.a = b0.a ))
LEFT JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS c1
FROM table3 t
WHERE t.e = "C") AS c0
ON ( t0.d = c0.d )
AND ( t0.c = c0.c )
AND ( t0.b = c0.b )
AND ( t0.a = c0.a ))
LEFT JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS d1
FROM table3 t
WHERE t.e = "D") AS d0
ON ( t0.d = d0.d )
AND ( t0.c = d0.c )
AND ( t0.b = d0.b )
AND ( t0.a = d0.a ))
LEFT JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS e1
FROM table3 t
WHERE t.e = "E") AS e0
ON ( t0.d = e0.d )
AND ( t0.c = e0.c )
AND ( t0.b = e0.b )
AND ( t0.a = e0.a );
Table3
ID a b c d e f
1 1 2 3 4 a €10.00
2 1 2 3 4 b €10.00
3 1 2 3 4 c €10.00
4 1 2 3 4 d €10.00
5 1 2 3 4 e €10.00
6 1 2 3 5 a €10.00
7 1 2 3 5 b
8 1 2 3 5 c €10.00
9 1 2 3 5 d €10.00
10 1 2 3 5 e €10.00
Result
There are two rows, because there are only two different sets in the first four columns.
a b c d an bn cn dn en
1 2 3 4 €10.00 €10.00 €10.00 €10.00 €10.00
1 2 3 5 €10.00 €0.00 €10.00 €10.00 €10.00
The way the sql above is supposed to work, is that it selects each of the four definition columns and the currency column from the table where the sort column has a particular sort letter and labels the currency column with the sort letter, each of these sub queries are then assembled, however, you can take a sub query and look at the results. The last one is the part between the parentheses:
INNER JOIN (SELECT t.a,
t.b,
t.c,
t.d,
t.f AS e1
FROM table3 t
WHERE t.e = "E") AS e0