Hierarchical Data Join of parent/child relationship in same table - mysql

I have the following table:
Id ParentId Weight
1 1 0
2 1 10
3 2 5
ParentId references Id of the same table. How can I query this table so that I join it on itself, adding up the cumulative weight of the third column?
For example, if I wanted to know the cumulative weight of Id 2, the result would return 15 (Id2 + Id3 = 15) as the parent of item 3 is 2. If I wanted to know the cumulative weight of item 3, it would return 5, as no records have a parent id of item 3.
Essentially, if the record I am querying has a child, I want to add the sequence of data's children and return one result.
Is this possible to do in one fell swoop to the database or would I have to loop through the entire record set to find matches?

Take a look on this article. If your table is not updated frequently, you can modify a little their GenericTree procedure that it generates all paths for all rows (and call it every time you insert record into the table or update ParentId column), store this data into a new table, and then you can perform all the tasks required using simple queries. Personally, I end up with the following table structure:
CREATE TABLE `tree_for_my_table` (
`rootID` INT(11) NOT NULL, // root node id
`parentID` INT(11) NOT NULL, // current parent id
`childID` INT(11) NOT NULL, // child id (direct child of the parent)
`level` INT(11) NOT NULL, // how far child is from root
PRIMARY KEY (`rootID`, `parentID`, `childID`),
UNIQUE INDEX `childID` (`childID`, `level`)
)
Populating data for that table doesn't take too long even for a quite large my_table.

Last I looked, mysql didn't have a built-in way of doing hierarchical queries, but you can always use a technique such as the adjacency list, discussed (among other techniques) in Managing Hierarchical Data in MySQL, which encodes the hierarchy in another table and lets you join against that to retrieve subtrees in your hierarchy.

You need to index your tree. See Managing Hierarchical Data in MySQL for some ways to do this.

Related

inserting multiple values into one row mySQL

How can i insert multiple values into one row?
My query
insert into table_RekamMedis values ('RM001', '1999-05-01', 'D01', 'Dr Zurmaini', 'S11', 'Tropicana', 'B01', 'Sulfa', '3dd1');
i cant insert two values into one row. is there another way to do it?
I'm ignorant of the human language you use, so this is a guess.
You have two entities in your system. One is dokter, the other is script (prescription). Your requirement is to store zero or more scripts for each dokter. That is, the relationship between your entities is one-to-many.
In a relational database management system (SQL system) you do that with two tables, one per entity. Your dokter table will contain a unique identifier for each doctor, and the doctor's descriptive attributes.
CREATE TABLE dokter(
dokter_id BIGINT AUTO_INCREMENT PRIMARY KEY NOT NULL,
nama VARCHAR (100),
kode VARCHAR(10),
/* others ... */
);
And you'll have a second table for script
CREATE TABLE script (
script_id BIGINT AUTO_INCREMENT PRIMARY KEY NOT NULL,
dokter_id BIGINT NOT NULL,
kode VARCHAR(10),
nama VARCHAR(100),
dosis VARCHAR(100),
/* others ... */
);
Then, when a doctor writes two prescriptions, you insert one row in dokter and two rows in script. You make the relationship between script and dokter by putting the correct dokter_id into each script row.
Then you can retrieve this information with a query like this:
SELECT dokter.dokter_id, dokter.nama, dokter.kode,
script.script_id, script.kode, script.nama, script.dosis
FROM dokter
LEFT JOIN script ON dokter.dokter_id = script.dokter_id
Study up on entity-relationship data design. It's worth your time to learn and will enhance your career immeasurably.
You can't store multiple values in a single field but there are various options to achieve what you're looking for.
If you know that a given field can only have a set number of values then it might make sense to simply create multiple columns to hold these values. In your case, perhaps Nama obat only ever has 2 different values so you could break out that column into two columns: Nama obat primary and Nama obat secondary.
But if a given field could have any amount of values, then it would likely make sense to create a table to hold those values so that it looks something like:
NoRM
NamaObat
RM001
Sulfa
RM001
Anymiem
RM001
ABC
RM002
XYZ
And then you can combine that with your original table with a simple join:
SELECT * FROM table_RekamMedis JOIN table_NamaObat ON table_RekamMedis.NoRM = table_NamaObat.NoRM
The above takes care of storing the data. If you then want to query the data such that the results are presented in the way you laid out in your question, you could combine the multiple NamaObat fields into a single field using GROUP_CONCAT which could look something like:
SELECT GROUP_CONCAT(NamaObat SEPARATOR '\n')
...
GROUP BY NoRM

MySQL bulk insertion: parent table autogenerated key into child table

We are doing migration from SQL Server 2012 to MySQL 5.6. One of the scenarios that came up is inserting bulk records in parent child table. An example:
create table parent (
parent_id int primary key auto_increment,
parent_name varchar(100) );
create table child (
child_id int primary key auto_increment,
child_name varchar(100) ,
foreign key (parent_id) references parent(parent_id));
Say I have two temp tables parent_temp and child_temp and I want to insert the records into parent and child tables. The problem is that I need to keep track of the auto-generated parent_id column with the parent_temp_id. In SQL Server, we used Output into statement to work around this problem. Since there is no direct method available here, here are some straight forward solutions that I could think of:
Do the insertion through entity framework.
Use a while loop to iterate the parent records and do an insertion in the parent table, get hold of the auto-generated key and insert into child table. And so on.
Add a spare column dummy_col in the parent table to hold the mapping. This will allow bulk inserts for parent table. The insert query looks like
insert into parent(parent_name,dummy_col )
select parent_temp_name, parent_temp_id from parent_temp
In this way we will have a 1-1 mapping between the rows of parent and parent_temp tables. The child table query looks like
insert into child(child_name,parent_id)
select child_temp_name, p.parent_id from child_temp ct
inner join parent p on p.dummy_col = ct.parent_temp_id
The problem with approaches 1 and 2 is that they are slow for bulk insertions. We could be inserting easily 15k rows at one time. Approach 3 will be problematic if two or more users are simultaneously running the same insertion query, and if their parent_temp_id's match since (we are using int, and they would be always be starting from 1,2,3,4...). If we use GUIDs instead of ints, we can probably avoid this duplicate issue. But we would always need to create extra columns in such tables and make sure that they are not used for some other purpose.
Based on the above scenario, are there any other solutions for MySQL? And which one would you prefer?

Omiting all heirachy data that matches on a JOIN with a one-to-many table

Basically, I've got a Heirarchal Tree Table
(buttons)
id INT(11),
name VARCHAR(80),
parent_id INT(11),
lft INT(11),
rght INT(11)
and a One-to-Many relationship to another table
(kiosk_buttons)
id INT(11),
kiosk_id INT(11) "foreign key to kiosk table",
button_id INT(11) "foreign key to buttons table"
I've been trying to omit the rows that have a matching buttons.id and kiosk_buttons.button_id while also omitting the children of the matching row.
Here is the query I currently have, it can omit rows but it can't omit it's children.
SELECT *
FROM buttons as b
LEFT JOIN kiosk_buttons as kb
ON b.id = kb.button_id
WHERE kb.button_id is NULL
SQL is simply the wrong concept for traversing and looping, it is made for Sets. So if you have a programming language to work with the data, you have to put the traversing there, in a form like your Query, followed by
SELECT *
FROM buttons as b
WHERE b.parent_id in (<last_button_list>)
while any results show. Work with that data and set the new list of button_ids as .
But if it comforts you: this way it is easier to work with the data, since a linear list with the whole tree is quite useless.

Getting unique record from a table in mysql

I have a problem in mysql. I need to fetch certain sets of records from a table that has the following data.
Let me brief you guys about the table. every primary item has a similar item and that similar item has a size.
but we have to show unique items from the above table having least size.
for example.. primary item is A and it's corresponding item in X and X is also primary and it's similar item in A but X also has a similar item P so A,X,P all are similar and in these the item with least size is P with size 4 so we have fetch P from the table with a query.
Furthermore the records are 1-M and all primary item as similar items and all similar items exits in the primary field in the database. And this table contain nearly 3 lacs record for fetching and looping one records at a time will not work..
Any help will be appreciate.
Thanks
Jawed Shamshedi
Given the schema:
CREATE TABLE similar_test ( id int(11) NOT NULL DEFAULT '0',
Stock varchar(20) NOT NULL, SimilarStock varchar(20) NOT NULL,
ItemSize decimal(18,2) DEFAULT '0.00' ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
please check this : I am considering for 1 level depth :
select * , s.ItemSize as minSize from similar_test as p
join similar_test a s on s.Stock= p.SimilarStock
where p.Sock='A'
order by s.itemSize
limit 1
If that is not addressing you questions as you said in comments the other options are :
a. create another table which will hold PRE- calculated values are desired
b. Write a stored procedure to go through the item list upto N-levels as N is unspecified
in this case (as I suspected)
c. Do the sorting and grouping in PHP/or any other language you are using
this might also help you hierarchical data
regards

Sphinx Search, compound key

After my previous question (http://stackoverflow.com/questions/8217522/best-way-to-search-for-partial-words-in-large-mysql-dataset), I've chosen Sphinx as the search engine above my MySQL database.
I've done some small tests with it, and it looks great. However, i'm at a point right now, where I need some help / opinions.
I have a table articles (structure isn't important), a table properties (structure isn't important either), and a table with values of each property per article (this is what it's all about).
The table where these values are stored, has the following structure:
articleID UNSIGNED INT
propertyID UNSIGNED INT
value VARCHAR(255)
The primary key is a compound key of articleID and propertyID.
I want Sphinx to search through the value column. However, to create an index in Sphinx, I need a unique id. I don't have right here.
Also when searching, I want to be able to filter on the propertyID column (only search values for propertyID 2 for example, which I can do by defining it as attribute).
On the Sphinx forum, I found I could create a multi-value attribute, and set this as query for my Sphinx index:
SELECT articleID, value, GROUP_CONCAT(propertyID) FROM t1 GROUP BY articleID
articleID will be unique now, however, now I'm missing values. So I'm pretty sure this isn't the solution, right?
There are a few other options, like:
Add an extra column to the table, which is unique
Create a calculated unique value in the query (like articleID*100000+propertyID)
Are there any other options I could use, and what would you do?
In your suggestions
Add an extra column to the table, which is unique
This can not be done for an existing table with large number of records as adding a new field to a large table take some time and during that time the database will not be responsive.
Create a calculated unique value in the query (like articleID*100000+propertyID)
If you do this you have to find a way to get the articleID and propertyID from the calculated unique id.
Another alternative way is that you can create a new table having a key field for sphinx and another two fields to hold articleID and propertyID.
new_sphinx_table with following fields
id - UNSIGNED INT/ BIGINT
articleID - UNSIGNED INT
propertyID - UNSIGNED INT
Then you can write an indexing query like below
SELECT id, t1.articleID, t1.propertyID, value FROM t1 INNER JOIN new_sphinx_table nt ON t1.articleID = nt.articleID AND t1.propertyID = nt.propertyID;
This is a sample so you can modify it to fit to your requirements.
What sphinx return is matched new_sphinx_table.id values with other attributed columns. You can get result by using new_sphinx_table.id values and joining your t1 named table and new_sphinx_table