Extended Metadata - mysql

The meta function in kdb/q returns the following info about the table:
c – (symbol) column names
t – (char) data type
f – (symbol) domain of foreign keys
a - (symbol) attributes.
I would like to extend this to include more information about the table. The specific case that I am trying to solve is to include the timezone information about the time data columns in the table.
For example:
select from Price
+-------------------------+-------------------------+--------+-------+
| Time | SysTime | Ticker | Price |
+-------------------------+-------------------------+--------+-------+
| 2016.09.15D09:18:02.391 | 2016.09.15D08:18:02.391 | IBM | 63.46 |
| 2016.09.15D09:18:02.491 | 2016.09.15D08:16:22.391 | MSFT | 96.72 |
| 2016.09.15D09:18:02.591 | 2016.09.15D08:14:42.391 | AAPL | 23.06 |
+-------------------------+-------------------------+--------+-------+
meta Price
+---------+---+---+---+
| c | t | f | a |
+---------+---+---+---+
| Time | p | | |
| SysTime | p | | |
| Ticker | s | | |
| Price | f | | |
+---------+---+---+---+
I would like to have additional info about the time data columns (Time and SysTime) in the meta.
For Example, something like this:
metaExtended Price
+---------+---+---+---+------------------+
| c | t | f | a | z |
+---------+---+---+---+------------------+
| Time | p | | | America/New_York |
| SysTime | p | | | America/Chicago |
| Ticker | s | | | |
| Price | f | | | |
+---------+---+---+---+------------------+
Please note that I have a function that takes in the table and column to return the time zone.
TimeZone[Price;Time] returns America/New_York
My question is only about how to include this information in the meta function. The second question that I have is that if the user does something like this, newPriceTable:Price (creating a new table which is the same as the previous table) then the metaExtended function should return the same value for both the tables (akin to calling a function on two different variables having the same object reference)
Does something similar exist in sql?

meta is a reserved word and therefore cannot be redefined. But you can create your own implementation and use it in place of meta:
TimeZone:{[Table;Col] ... } / your TimeZone function
metaExtended:{meta[x],'([]z:TimeZone[t]each cols x)}
metaExtended Price
Regarding your second question, I don't think it's possible to do what you want in k/q. Immediately after assigning Price to newPriceTable the latter is indeed a reference, but as soon as you modify it kdb will create a copy and modify it instead of the original. The problem is there is no way to tell whether newPriceTable is still a reference to Price or a fresh new object.

You can use lj to join them into one metaExtended function.
The function will check for all the time cols and run TimeZone function on them and join the result with meta result:
metaExtended:{[tbl] meta[tbl] lj 1!select c,z:TimeZone[tbl] each t from meta[tbl] where t in "tp"}
metaExtended `t
when you assign this table to new variable it will be assigned as a reference.
nt:t / nt and t pointing to same object
Yo can check the reference count of a variable using -16! .
-16!t
At this point metaExtended function will give same output. But once some update is done on any of these variables pointing to same table, kdb will create a new copy for updated table/variable. From this point they are 2 different objects. Now output of metaExtended function depends on the object schema.

Related

MySQL - Recursive - getting email addresses from 2 different tables and columns

I have a first table called emails with a list of all the emails of my colleagues
| email |
| ----------------------- |
| saramaia#email.com |
| miguelferreira#email.com |
| joaosilva#email.com |
| joanamaia#email.com |
I have a second table called aliases, with a list of all the secondary emails/aliases my colleagues are using
| alias1 | alias2 |
| ------------------------ | ------------------- |
| joanamaia#email.com | maiajoana#email.com |
| maiajoana#email.com | maia#email.com |
| miguelferreira#email.com | miguel#email.com |
| maia#email.com | joana#email.com |
| joanamaia#email.com | jomaia#email.com |
| joana#email.com | jmaia#email.com |
I can see that the users joanamaia#email.com and miguelferreira#email.com are using aliases. But let's focus on the user joanamaia#email.com.
I need to get a list of all the email addresses the user joanamaia#email.com is using. The difficult part is that I need to get a list with the main email address plus all the intersections where the first email and consecutive ones are being used by this user. The end result should look like this
| emails |
| ------------------- |
| joanamaia#email.com |
| jomaia#email.com |
| maiajoana#email.com |
| maia#email.com |
| joana#email.com |
| jmaia#email.com |
If I do WHERE email='joanamaia#email.com' it should look like this, but I also need the same result if I do
WHERE email='jmaia#email.com'
I've been through some days of testing queries and I don't seem to have a solution for this (I've been using right joins, full outer joins and unions, but no luck so far). Is there a good way to do this?
You can use a recursive CTE to walk the graph and get the full list of interconnected aliases. Care needs to be taken to handle cycles; that requires the query to use UNION instead of the traditional UNION ALL to separate the anchor and recursive member of the CTE.
The query can take the form:
with recursive
n as (
select 'joanamaia#email.com' as email
union
select case when a.alias1 = n.email then a.alias2 else a.alias1 end
from n
join aliases a on (a.alias1 = n.email or a.alias2 = n.email)
and a.alias1 <> a.alias2
)
select * from n;
Result:
email
-------------------
joanamaia#email.com
maiajoana#email.com
jomaia#email.com
maia#email.com
joana#email.com
jmaia#email.com
See running example at DB Fiddle.

FDQuery and OnCalcFields, get the previous line

Delphi 10.3.3
FireDAC: DBGrid / FDQuery / MySQL
VCL
Hi all,
I have a table with these fields
----------------------
| id | data |
----------------------
| 1 | 0=A;1=B;2=C |
| 2 | 2=Z |
| 3 | |
| 4 | 0=Y;1=X |
| 5 | |
| 6 | |
Each row of data represents only the change in the table
I would like this to be display in a DBGRID:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | A | B | Z |
| 3 | A | B | Z |
| 4 | Y | X | Z |
| 5 | Y | X | Z |
| 6 | Y | X | Z |
What I can do for now is only the following table:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | | | Z |
| 3 | | | |
| 4 | Y | X | |
| 5 | | | |
| 6 | | | |
To obtain this result, I create additional columns in the event FDQuery1.BeforeOpen
And in the event OnCreateFields, I fill each column but I don't know the previous row content,
So, how can I do to fill in the missing fields in the DBgrid?
Thanks
Franck
I think you mean OnCalcFields, rather than OnCreateFields.
What you need
is certainly possible, either server-side by deriving the necessary values from the prior
row using e.g. a SQL subquery or client-side using calculated fields. This answer is about doing it
client-side.
The problem with doing client-side calculations involving another dataset row is that
to do this you need to be able to move the dataset cursor during the OnCalcFields event. However, at the time, the DataSet will be in either dsCalcFields or dsInternalCalc state
and, while it is, you can't easily move to another row in the dataset. It is possible to do this, but
requires declaring a descendant dataset class (TMyFDQuery) so that you can access the SetTempState
necessary to do revert to the prior state after you've picked up the necessary info from the "other"
row and, if what you need involves more that one field, you need somewhere to store the values temporarily.
So doing it that way gets messy.
A much cleaner approach involves using functional similarity between FireDAC's datasets and TClientDataSets.
One of the nice features of TClientDatasSets is the ease with which you can move the dataset contents between
two CDSs simply by doing
CDS2.Data := CDS1.Data;
FireDAC datasets can do the same trick, but between any FD dataset types. So here is what I would do in your
situation:
Add an FDMemTable to your form/datamodule and copy the query data into it in the FDQuery's AfterOpen event like
this:
procedure TForm2.FDQuery1AfterOpen(DataSet: TDataSet);
begin
FDQuery1.DisableControls;
try
FDMemTable1.Data := FDQuery1.Data;
FDMemTable1.Open;
finally
FDQuery1.First;
FDQuery1.EnableControls;
end;
end;
The FDQuery1.First is to force it to re-do its calculated fields once the FDMemTable data is available
(during the initial FDQuery1.Open, it can't be, of course).
In the FDQuery's OnCalcFields event, use code like this to base the calculated fields'
values on values picked up from the prior row (if there is one of course, the first
row can't hae a "prior" row):
procedure TForm2.FDQuery1CalcFields(DataSet: TDataSet);
begin
if FDMemTable1.Active then begin
if FDMemTable1.Locate('ContactID', FDQuery1.FieldByName('ContactID').AsInteger, []) then begin
FDMemTable1.Prior;
if not FDMemTable1.Bof then begin
// Set FDQuery1's calculated fields that depend on prior row
FDQuery1.FieldByName('PriorRowID').AsInteger := FDMemTable1.FieldByName('ContactID').AsInteger;
end;
end;
end;
end;
In this example, my queried dataset has a ContactID primary key and the calculated value is simply the ContactID value from the prior row. In real life, of course, it
would be more efficient to use persistent field variables rather than keep calling FieldByName.
I suppose another possibility might be to use the CloneCursor method to obtain a lookup cursor
to access the "prior" row, but I've not tried that myself and it may not be possible anyway
(what happens about the calculated fields in the CloneCuror copy?).

grails - findBy highest id AND another criteria

I've looked a bunch of answers to this question here on SO and elsewhere but all I can track down is cases where people just want to find the highest id, the max dateCreated or the latest db entry but what I want to do is retrieve the latest object created that also matches another criteria. My domain class has the following properties: id, number, company, type, dateCreated and content. The company property can only be set to 'OYG' or 'BAW' and the number property is an auto incrementing int. What I want to do is retrieve the record with the highest number that also has its company property set to 'OYG' or 'BAW`.
So here's an example:
+----------------------------------------------------------+
| id | number | company | type | dateCreated | content |
+----------------------------------------------------------+
| 1 | 0 | OYG | TsAndCs | 15/09/2016 | stuff |
| 2 | 0 | BAW | TsAndCs | 15/09/2016 | stuff |
| 3 | 1 | OYG | TsAndCs | 16/09/2016 | stuff |
| 4 | 2 | OYG | TsAndCs | 17/09/2016 | stuff |
| 5 | 1 | BAW | TsAndCs | 16/09/2016 | stuff |
+----------------------------------------------------------+
I want to say def doc = Document.findByHighestNumberAndCompany('OYG') then it should bring back the object with id 4. def doc = Document.findByHighestNumberAndCompany('BAW') should bring back id 5's object, etc.
Any help would be appreciated. Thanks!
Despite Joshua Moore gave you a good solution, there is another simplier in one line.
MyDomain.findAllByCompany(company, [sort: 'number', order: 'desc', limit: 1])?.first()
Should be easy enough if you order by the number in descending order, and limit your results to one. So perhaps something like this?
String companyName = 'OYG'
def results = MyDomain.createCriteria().list() {
eq("company", companyName)
maxResults(1)
order("number", "desc")
}
println results[0].id // will print 4
Using this approach you could create a named query so you can pass the company name as a parameter.

How to replace substring in mysql where string is based on other table-column values

I have two mysql tables as
Component
+----+-------------------------+--------+
| OldComponentId | NewComponentId |
+----+-------------------------+--------+
| 15 | 85 |
| 16 | 86 |
| 17 | 87 |
+----+-------------------------+--------+
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+15-16+17 |
| 2 | 16+15-17 |
+----+-------------------------+--------+
I want to replace value of formula_string on the basis of NewComponentId as
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+85-86+87 |
| 2 | 86+85-87 |
+----+-------------------------+--------+
I have tried with following mysql query but its not working
update Formulae fr, Component comp set formula_string=REPLACE(fr.formula_string,comp.OldComponentId,comp.NewComponentId).
Please suggest the solutions
thanks.
There is no easy way to do this. As you observed in your update statement, the replacements don't nest. They just replace one at a time.
One thing that you can do is:
update Formulae fr cross join
Component comp
set formula_string = REPLACE(fr.formula_string, comp.OldComponentId, comp.NewComponentId)
where formula_string like concat('%', comp.OldComponentId, '%')
Then continue running this until row_count() returns 0.
Do note that your structure could result in infinite loops (if A --> B and B --> A). You also have a problem of "confusion" so 10 would be replaced in 100. This suggests that your overall data structure may not be correct. Perhaps you should break up the formula into separate pieces. If they are just numbers and + and -, you can have a junction table with the value and the sign for each component. Then your query would be much easier.

How to split CSVs from one column to rows in a new table in MSSQL 2008 R2

Imagine the following (very bad) table design in MSSQL2008R2:
Table "Posts":
| Id (PK, int) | DatasourceId (PK, int) | QuotedPostIds (nvarchar(255)) | [...]
| 1 | 1 | | [...]
| 2 | 1 | 1 | [...]
| 2 | 2 | 1 | [...]
[...]
| 102322 | 2 | 123;45345;4356;76757 | [...]
So, the column QuotedPostIds contains a semicolon-separated list of self-referencing PostIds (Kids, don't do that at home!). Since this design is ugly as a hell, I'd like to extract the values from the QuotedPostIds table to a new n:m relationship table like this:
Desired new table "QuotedPosts":
| QuotingPostId (int) | QuotedPostId (int) | DatasourceId (int) |
| 2 | 1 | 1 |
| 2 | 1 | 2 |
[...]
| 102322 | 123 | 2 |
| 102322 | 45345 | 2 |
| 102322 | 4356 | 2 |
| 102322 | 76757 | 2 |
The primary key for this table could either be a combination of QuotingPostId, QuotedPostId and DatasourceID or an additional artificial key generated by the database.
It is worth noticing that the current Posts table contains about 6,300,000 rows but only about 285,000 of those have a value set in the QuotedPostIds column. Therefore, it might be a good idea to pre-filter those rows. In any case, I'd like to perform the normalization using internal MSSQL functionality only, if possible.
I already read other posts regarding this topic which mostly dealt with split functions but neither could I find out how exactly to create the new table and also copying the appropriate value from the Datasource column, nor how to filter the rows to touch accordingly.
Thank you!
€dit: I thought it through and finally solved the problem using an external C# program instead of internal MSSQL functionality. Since it seems that it could have been done using Mikael Eriksson's suggestion, I will mark his post as an answer.
From comments you say you have a string split function that you you don't know how to use with a table.
The answer is to use cross apply something like this.
select P.Id,
S.Value
from Posts as P
cross apply dbo.Split(';', P.QuotedPostIds) as S