Retrieve top-level parent MySQL - mysql

I have the following table:
id | parent_id | searchable | value
--------------------------------------------
1 | 0 | 0 | a
2 | 1 | 0 | b
3 | 2 | 1 | c
4 | 0 | 0 | d
5 | 4 | 1 | e
6 | 0 | 0 | f
7 | 6 | 0 | g
8 | 6 | 0 | h
9 | 0 | 1 | i
I need to extract all the top level records (so the ones where the parent_id = 0).
But only the records where the parent OR one of his children is searchable (searchable = 1)
So in this case, the output should be:
id | parent_id | searchable | value
--------------------------------------------
1 | 0 | 0 | a
4 | 0 | 0 | d
9 | 0 | 1 | i
Because these are all top-level records and it self or one of his childeren (doesn't matter how 'deep' the searchable child is) is searchable.
I am working with MySQL. I am not really sure if it is possible to write this with just one query, but I assume it should be done with a piece of recursive code or a function.
** Note: it is unknown how 'deep' the tree goes.

You will have to use stored procedure to do it.
Find all rows with searchable = 1, store their ids and parent_ids in a temp table.
Then do self-joins to add parents to this temp table.
Repeat until no more rows can be added (obviously better make sure tree is not cyclic).
At the end you have a table only with rows that have a searchable descendant somewhere down the tree, so just show only rows with no parent (at the top).
Assuming your table is called 'my_table' this one should work:
DELIMITER //
DROP PROCEDURE IF EXISTS top_level_parents//
CREATE PROCEDURE top_level_parents()
BEGIN
DECLARE found INT(11) DEFAULT 1;
DROP TABLE IF EXISTS parent_tree;
CREATE TABLE parent_tree (id int(11) PRIMARY KEY, p_id int(11)) ENGINE=HEAP;
INSERT INTO parent_tree
SELECT id, parent_id FROM my_table
WHERE searchable = 1;
SET found = ROW_COUNT();
WHILE found > 0 DO
INSERT IGNORE INTO parent_tree
SELECT p.id, p.parent_id FROM parent_tree c JOIN my_table p
WHERE p.id = c.p_id;
SET found = ROW_COUNT();
END WHILE;
SELECT id FROM parent_tree WHERE p_id = 0;
DROP TABLE parent_tree;
END;//
DELIMITER ;
Then just calling it:
CALL top_level_parents();
will be equal to
SELECT id FROM my_table WHERE id_is_top_level_and_has_searchable_descendant

Recursive queries can be done in Newer Mysql, possibly not around back when this was asked.
Get parents and children data where top level parent has a name of "A" or "B" or "C".
RECURSIVE MySQL 8.0 compatibility.
https://dev.mysql.com/doc/refman/8.0/en/with.html
The first part gets the parent top level and filters it, the second gets the children joining to their parents.
WITH RECURSIVE tree AS (
SELECT id,
name,
parent_id,
1 as level
FROM category
WHERE parent_id = 0 AND (name = 'A' or name = 'B' or name = 'C')
UNION ALL
SELECT c.id,
c.name,
c.parent_id,
t.level + 1
FROM category c
JOIN tree t ON c.parent_id = t.id
)
SELECT *
FROM tree;
To find if the parent or one of its children have searchable, you can pull through that value with a COALESCE(NULLIF(p.searchable,0), NULLIF(c.searchable,0)) and by pulling through the top level parent id and joining back against it.
So to initialize your example data:
CREATE TABLE `category` (
`id` int(11) NOT NULL,
`parent_id` int(11) NULL DEFAULT NULL,
`searchable` int(11) NULL DEFAULT NULL,
`value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
INSERT INTO category (id, parent_id, searchable, value) VALUES
(1,0,0,'a'),
(2,1,0,'b'),
(3,2,1,'c'),
(4,0,0,'d'),
(5,4,1,'e'),
(6,0,0,'f'),
(7,6,0,'g'),
(8,6,0,'h'),
(9,0,1,'i');
And to answer the question.
WITH RECURSIVE tree AS (
SELECT id,
value,
parent_id,
1 as level,
searchable,
id AS top_level_id
FROM category
WHERE parent_id = 0
UNION ALL
SELECT c.id,
c.value,
c.parent_id,
t.level + 1,
COALESCE(NULLIF(t.searchable,0), NULLIF(c.searchable,0)),
COALESCE(t.top_level_id) AS top_level_id
FROM category c
JOIN tree t ON c.parent_id = t.id
)
SELECT category.*
FROM category
LEFT JOIN tree ON tree.top_level_id = category.id
WHERE tree.searchable = 1;
Note: Does not handle cyclic linkages.
If you have those, you need to remove them or constraint it so it does not happen, or add a visited column in much the same way you can bring through the top level id possibly.

Related

SQL where not exists with multiple rows and status

I have the following tables (minified for the sake of simplicity):
CREATE TABLE IF NOT EXISTS `product_bundles` (
bundle_id int AUTO_INCREMENT PRIMARY KEY,
-- More columns here for bundle attributes
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `product_bundle_parts` (
`part_id` int AUTO_INCREMENT PRIMARY KEY,
`bundle_id` int NOT NULL,
`sku` varchar(255) NOT NULL,
-- More columns here for product attributes
KEY `bundle_id` (`bundle_id`),
KEY `sku` (`sku`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `products` (
`product_id` mediumint(8) AUTO_INCREMENT PRIMARY KEY,
`sku` varchar(64) NOT NULL DEFAULT '',
`status` char(1) NOT NULL default 'A',
-- More columns here for product attributes
KEY (`sku`),
) ENGINE=InnoDB;
And I want to show only the 'product bundles' that are currently completely in stock and defined in the database (since these get retrieved from a third party vendor, there is no guarantee the SKU is defined). So I figured I'd need an anti-join to retrieve it accordingly:
SELECT SQL_CALC_FOUND_ROWS *
FROM product_bundles AS bundles
WHERE 1
AND NOT EXISTS (
SELECT *
FROM product_bundle_parts AS parts
LEFT JOIN products AS products ON parts.sku = products.sku
WHERE parts.bundle_id = bundles.bundle_id
AND products.status = 'A'
AND products.product_id IS NULL
)
-- placeholder for other dynamic conditions for e.g. sorting
LIMIT 0, 24
Now, I sincerely thought this would filter out the products by status, however, that seems not to be the case. I then changed one thing up a bit, and the query never finished (although I believe it to be correct):
SELECT SQL_CALC_FOUND_ROWS *
FROM product_bundles AS bundles
WHERE 1
AND NOT EXISTS (
SELECT *
FROM product_bundle_parts AS parts
LEFT JOIN products AS products ON parts.sku = products.sku
AND products.status = 'A'
WHERE parts.bundle_id = bundles.bundle_id
AND products.product_id IS NULL
)
-- placeholder for other dynamic conditions for e.g. sorting
LIMIT 0, 24
Example data:
product_bundles
bundle_id | etc.
1 |
2 |
3 |
product_bundle_parts
part_id | bundle_id | sku
1 | 1 | 'sku11'
2 | 1 | 'sku22'
3 | 1 | 'sku33'
4 | 1 | 'sku44'
5 | 2 | 'sku55'
6 | 2 | 'sku66'
7 | 3 | 'sku77'
8 | 3 | 'sku88'
products
product_id | sku | status
101 | 'sku11' | 'A'
102 | 'sku22' | 'A'
103 | 'sku33' | 'A'
104 | 'sku44' | 'A'
105 | 'sku55' | 'D'
106 | 'sku66' | 'A'
107 | 'sku77' | 'A'
108 | 'sku99' | 'A'
Example result: Since the product status of product #105 is 'D' and 'sku88' from part #8 was not found:
bundle_id | etc.
1 |
I am running Server version: 10.3.25-MariaDB-0ubuntu0.20.04.1 Ubuntu 20.04
So there are a few questions I have.
Why does the first query not filter out products that do not have the status A.
Why does the second query not finish?
Are there alternative ways of achieving the same thing in a more efficient matter, as this looks rather cumbersome.
First of all, I've read that SQL_CALC_FOUND_ROWS * is much slower than running two separate query (COUNT(*) and then SELECT * or, if you make your query inside another programming language, like PHP, executing the SELECT * and then count the number of rows of the result set)
Second: your first query returns all the boundles that doesn't have ANY active products, while you need the boundles with ALL products active.
I'd change it in the following:
SELECT SQL_CALC_FOUND_ROWS *
FROM product_bundles AS bundles
WHERE NOT EXISTS (
SELECT 'x'
FROM product_bundle_parts AS parts
LEFT JOIN products ON (parts.sku = products.sku)
WHERE parts.bundle_id = bundles.bundle_id
AND COALESCE(products.status, 'X') != 'A'
)
-- placeholder for other dynamic conditions for e.g. sorting
LIMIT 0, 24
I changed the products.status = 'A' in products.status != 'A': in this way the query will return all the boundles that DOESN'T have inactive products (I also removed the condition AND products.product_id IS NULL because it should have been in OR, but with a loss in performance).
You can see my solution in SQLFiddle.
Finally, to know why your second query doesn't end, you should check the structure of your tables and how they are indexed. Executing an Explain on the query could help you to find eventual issues on the structure. Just put the keyword EXPLAIN before the SELECT and you'll have your "report" (EXPLAIN SELECT * ....).

Find two closest elements from one table to other element from another table

I have two tables:
DROP TABLE IF EXISTS `left_table`;
CREATE TABLE `left_table` (
`l_id` INT(11) NOT NULL AUTO_INCREMENT,
`l_curr_time` INT(11) NOT NULL,
PRIMARY KEY(l_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `right_table`;
CREATE TABLE `right_table` (
`r_id` INT(11) NOT NULL AUTO_INCREMENT,
`r_curr_time` INT(11) NOT NULL,
PRIMARY KEY(r_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO left_table(l_curr_time) VALUES
(3),(4),(6),(10),(13);
INSERT INTO right_table(r_curr_time) VALUES
(1),(5),(7),(8),(11),(12);
I want to map (if exists) two closest r_curr_time from right_table to each l_curr_time from left_table such that r_curr_time must be greater or equal to l_curr_time.
The expected result for given values should be:
+------+-------------+-------------+
| l_id | l_curr_time | r_curr_time |
+------+-------------+-------------+
| 1 | 3 | 5 |
| 1 | 3 | 7 |
| 2 | 4 | 5 |
| 2 | 4 | 7 |
| 3 | 6 | 7 |
| 3 | 6 | 8 |
| 4 | 10 | 11 |
| 4 | 10 | 12 |
+------+-------------+-------------+
I have following solution which works for one closest value. But I do not like it very much because it silently rely on fact that GROUP BY will remain the first occurrence from group:
SELECT l_id, l_curr_time, r_curr_time, time_diff FROM
(
SELECT *, ABS(r_curr_time - l_curr_time) AS time_diff
FROM left_table
JOIN right_table ON 1=1
WHERE r_curr_time >= l_curr_time
ORDER BY l_id ASC, time_diff ASC
) t
GROUP BY l_id;
The output is following:
+------+-------------+-------------+-----------+
| l_id | l_curr_time | r_curr_time | time_diff |
+------+-------------+-------------+-----------+
| 1 | 3 | 5 | 2 |
| 2 | 4 | 5 | 1 |
| 3 | 6 | 7 | 1 |
| 4 | 10 | 11 | 1 |
+------+-------------+-------------+-----------+
4 rows in set (0.00 sec)
As you can see I am doing JOIN ON 1=1 is this OK also for large data (e.g. if both left_table and right_table has 10000 rows then Cartesian product will be 10^8 long)? Despite this lack I thing JOIN ON 1=1 is the only possible solution because first I need to create all possible combinations from existing tables and then pick up the ones which satisfies the condition, but if I'm wrong please correct me. Thanks.
This question is not trivial. In SQL Server or postgrsql it would be very easy because of the row_number() over x statement. This is not present in mysql. In mysql you have to deal with variables and chained select statements.
To solve this problem you have to combine multiple concepts. I will try to explain them one after the other to came to a solution that fits your question.
Lets start easy: How to build a table that contains the information of left_table and right_table?
Use a join. In this particular problem a left join and as the join condition we set that l_curr_time has to be smaller than r_curr_time. To make the rest easier we order this table by l_curr_time and r_curr_time. The statement is like the following:
SELECT l_id, l_curr_time, r_curr_time
FROM left_table l
LEFT JOIN right_table r ON l.l_curr_time<r.r_curr_time
ORDER BY l.l_curr_time, r.r_curr_time;
Now we have a table that is ordered and contains the information we want... but too many of them ;) Because the table is ordered it would be amazing if mysql could select only the two first occurent rows for each value in l_curr_time. This is not possible. We have to do it by ourselfs
mid part: How to number rows?
Use a variable! If you want to number a table you can use a mysql variable. There are two things to do: First of all we have to declare and define the variable. Second we have to increment this variable. Let's say we have a table with names and we want to know the position of all names when we order them by name:
SELECT name, #num:=#num+1 /* increment */
FROM table t, (SELECT #num:=0) as c
ORDER BY name ASC;
Hard part: How to number subset of rows depending of the value of one field?
Use variables to count (take a look above) and a variable for state pattern. We use the same principe like above but now we take a variable and save the value of the field we want depend on. If the value changes we reset the counter variable to zero. Again: This second variable have to be declared and defined. New Part: resetting a different variable depending on the content of the state variable:
SELECT
l_id,
l_curr_time,
r_curr_time,
#num := IF( /* (re)set num (the counter)... */
#l_curr_time = l_curr_time,
#num:= #num + 1, /* increment if the variable equals the actual l_curr_time field value */
1 /* reset to 1 if the values are not equal */
) as row_num,
#l_curr_time:=l_curr_time as lct /* state variable that holds the l_curr_time value */
FROM ( /* table from Step 1 of the explanation */
SELECT l_id, l_curr_time, r_curr_time
FROM left_table l
LEFT JOIN right_table r ON l.l_curr_time<r.r_curr_time
ORDER BY l.l_curr_time, r.r_curr_time
) as joinedTable
Now we have a table that holds all combinations we want (but too many) and all rows are numbered depending on the value of the l_curr_time field. In other words: Each subset is numbered from 1 to the amount of matching r_curr_time values that are greather or equal than l_curr_time.
Again the easy part: select all the values we want and depending on the row number
This part is easy. because the table we created in 3. is ordered and numbered we can filter by the number (it has to be smaller or equal to 2). Furthermore we select only the columns we're interessted in:
SELECT l_id, l_curr_time, r_curr_time, row_num
FROM ( /* table from step 3. */
SELECT
l_id,
l_curr_time,
r_curr_time,
#num := IF(
#l_curr_time = l_curr_time,
#num:= #num + 1,
1
) as row_num,
#l_curr_time:=l_curr_time as lct
FROM (
SELECT l_id, l_curr_time, r_curr_time
FROM left_table l
LEFT JOIN right_table r ON l.l_curr_time<r.r_curr_time
ORDER BY l.l_curr_time, r.r_curr_time
) as joinedTable
) as numberedJoinedTable,(
SELECT #l_curr_time:='',#num:=0 /* define the state variable and the number variable */
) as counterTable
HAVING row_num<=2; /* the number has to be smaller or equal to 2 */
That's it. This statement returns exactly what you want. You can see this statement in action in this sqlfiddle.
JoshuaK has the right idea. I just think it could be expressed a little more succinctly...
How about:
SELECT n.l_id
, n.l_curr_time
, n.r_curr_time
FROM
( SELECT a.*
, CASE WHEN #prev = l_id THEN #i:=#i+1 ELSE #i:=1 END i
, #prev := l_id prev
FROM
( SELECT l.*
, r.r_curr_time
FROM left_table l
JOIN right_table r
ON r.r_curr_time >= l.l_curr_time
) a
JOIN
( SELECT #prev := null,#i:=0) vars
ORDER
BY l_id,r_curr_time
) n
WHERE i<=2;

MySQL: Merge tables, run SELECT and update duplicates

I've the following three tables:
Table A:
id VARCHAR(32) | value VARCHAR(32) | groupId INT
abcdef | myValue1 | 1
ghijkl | myValue2 | 2
mnopqr | myValue3 | 1
Table B:
id VARCHAR(32) | value VARCHAR(32) | userId INT
abcdef | myValue4 | 1
uvwxyz | anotherValue | 1
Table C:
id VARCHAR(32) | someOtherColumns...
abcdef
ghijkl
mnopqr
...
uvwxyz
Table A and B are used for a m:n-association, thus the "id"-column in both tables references the same field ("id"-column in table c).
What I want to do is (for instance)... select all entries in table A where groupId = 1
SELECT * FROM TableA WHERE groupId = 1
and also select all entries in table B where userId = 1
SELECT * FROM TableB WHERE userId = 1
That's all no problem... but the following makes the select-statement(s) difficult: How can I merge both select-results and replace the value of the first result? For example:
selecting all entries in Table A where groupId = 1 I'll get abcdef and also mnopqr.
when I select all entries in Table B where userId = 1 I'll also get abdef (and additionally uvwxyz).
Now, the value of abcdef in Table B should replace the value in the selection result of table A. And the uvwxyz-entry should be added to the result.
Finally I'm looking for a query which produces the following table:
id VARCHAR(32) | value VARCHAR(32)
abcdef | myValue4 -- myValue1 from the select-statement in tableA should be overwritten
mnopqr | myValue2 -- from table A
uvwxyz | anotherValue -- from table B
I hope anyone know how to do this... thanks in advance for any suggestion! By the way... it would be great if there is any chance to realize this using one single (long) select statement.
Try this:
SELECT * FROM TableB WHERE userId = 1
UNION
SELECT * FROM TableA WHERE groupId = 1
and id not in (select id from TableB where userid = 1)
#rs points out to use the UNION, which is required since MySQL doesn't have FULL joins.
Favoring the data from table B is a chose for CASE:
select id, case when max(value_b) is not null then max(value_b) else max(value_a) end as final_value
from (
select id, value as 'value_a', null as 'value_b' from tableA
union
select id, null, value from tableB
) ugh
group by 1;

mySQL hierarchical grouping sort

I have a schema that essentially looks like this:
CREATE TABLE `data` (
`id` int(10) unsigned NOT NULL,
`title` text,
`type` tinyint(4),
`parent` int(10)
)
The type field is just an enum where 1 is a parent type, and 2 is a child type (in actuality there are many types, where some should behave like parents and some like children). The parent field indicates that a record is the child of another record.
I know this is probably not ideal for the query I want to build, but this is what I have to work with.
I would like to sort and group the data so that the parent records are sorted by title, and grouped under each parent is the child records sorted by title. Like so:
ID | title |type |parent
--------------------------------
4 | ParentA | 1 |
2 | ChildA | 2 | 4
5 | ChildB | 2 | 4
7 | ParentB | 1 |
9 | ChildC | 2 | 7
1 | ChildD | 2 | 7
** Edit **
We should be able to take the type field out of the picture entirely. If parent is not null then it should be grouped underneath it's parent.
SELECT * FROM `data` ORDER BY COALESCE(`parent`, `id`), `parent`, `id`
Here's a solution tested to work on SQL Server. Should be essentially the same on MySQL
select Id, Title, [Type], Id as OrderId from Hier h1 where [Type] = 1
union
select Id, Title, [Type], Parent as OrderId from Hier h2 where [Type] = 2
order by OrderId, [Type]
You said you wanted it to sort on the titles, correct?
SELECT id, title, parent
FROM
( SELECT id, title, parent,
CASE WHEN parent is null THEN title ELSE CONCAT((SELECT title FROM `data` d2 WHERE d2.id = d.parent), '.', d.title) END AS sortkey
FROM `data` d
) subtable
ORDER BY sortkey
edit: Edited to remove type from the query.

Mysql unique values query

I have a table with name-value pairs and additional attribute. The same name can have more than one value. If that happens I want to return the row which has a higher attribute value.
Table:
ID | name | value | attribute
1 | set1 | 1 | 0
2 | set2 | 2 | 0
3 | set3 | 3 | 0
4 | set1 | 4 | 1
Desired results of query:
name | value
set2 | 2
set3 | 3
set1 | 4
What is the best performing sql query to get the desired results?
the best performing query would be as follows:
select
s.set_id,
s.name as set_name,
a.attrib_id,
a.name as attrib_name,
sav.value
from
sets s
inner join set_attribute_values sav on
sav.set_id = s.set_id and sav.attrib_id = s.max_attrib_id
inner join attributes a on sav.attrib_id = a.attrib_id
order by
s.set_id;
+--------+----------+-----------+-------------+-------+
| set_id | set_name | attrib_id | attrib_name | value |
+--------+----------+-----------+-------------+-------+
| 1 | set1 | 3 | attrib3 | 20 |
| 2 | set2 | 0 | attrib0 | 10 |
| 3 | set3 | 0 | attrib0 | 10 |
| 4 | set4 | 4 | attrib4 | 10 |
| 5 | set5 | 2 | attrib2 | 10 |
+--------+----------+-----------+-------------+-------+
obviously for this to work you're gonna also have to normalise your design and implement a simple trigger:
drop table if exists attributes;
create table attributes
(
attrib_id smallint unsigned not null primary key,
name varchar(255) unique not null
)
engine=innodb;
drop table if exists sets;
create table sets
(
set_id smallint unsigned not null auto_increment primary key,
name varchar(255) unique not null,
max_attrib_id smallint unsigned not null default 0,
key (max_attrib_id)
)
engine=innodb;
drop table if exists set_attribute_values;
create table set_attribute_values
(
set_id smallint unsigned not null,
attrib_id smallint unsigned not null,
value int unsigned not null default 0,
primary key (set_id, attrib_id)
)
engine=innodb;
delimiter #
create trigger set_attribute_values_before_ins_trig
before insert on set_attribute_values
for each row
begin
update sets set max_attrib_id = new.attrib_id
where set_id = new.set_id and max_attrib_id < new.attrib_id;
end#
delimiter ;
insert into attributes values (0,'attrib0'),(1,'attrib1'),(2,'attrib2'),(3,'attrib3'),(4,'attrib4');
insert into sets (name) values ('set1'),('set2'),('set3'),('set4'),('set5');
insert into set_attribute_values values
(1,0,10),(1,3,20),(1,1,30),
(2,0,10),
(3,0,10),
(4,4,10),(4,2,20),
(5,2,10);
This solution will probably perform the best:
Select ...
From Table As T
Left Join Table As T2
On T2.name = T.name
And T2.attribute > T1.attribute
Where T2.ID Is Null
Another solution which may not perform as well (you would need to evaluate against your data):
Select ...
From Table As T
Where Not Exists (
Select 1
From Table As T2
Where T2.name = T.name
And T2.attribute > T.attribute
)
select name,max(value)
from table
group by name
SELECT name, value
FROM (SELECT name, value, attribute
FROM table_name
ORDER BY attribute DESC) AS t
GROUP BY name;
There is no easy way to do this.
A similar question was asked here.
Edit: Here's a suggestion:
SELECT `name`,`value` FROM `mytable` ORDER BY `name`,`attribute` DESC
This isn't quite what you asked for, but it'll at least give you the higher attribute values first, and you can ignore the rest.
Edit again: Another suggestion:
If you know that value is a positive integer, you can do this. It's yucky, but it'll work.
SELECT `name`,CAST (GROUP_CONCAT(`value` ORDER by `attribute` DESC) as UNSIGNED) FROM `mytable` GROUP BY `name`
To include negative integers you could change UNSIGNED to SIGNED.
Might want to benchmark all these options, here's another one.
SELECT t1.name, t1.value
FROM temp t1
WHERE t1.attribute IN (
SELECT MAX(t2.attribute)
FROM temp t2
WHERE t2.name = t1.name);
How about:
SELECT ID, name, value, attribute
FROM table A
WHERE A.attribute = (SELECT MAX(B.attribute) FROM table B WHERE B.NAME = A.NAME);
Edit: Seems like someones said the same already.
Did not benchmark them, but here is how it is doable:
TableName = temm
1) Row with maximum value of attribute :
select t.name, t.value
from (
select name, max(attribute) as maxattr
from temm group by name
) as x inner join temm as t on t.name = x.name and t.attribute = x.maxattr;
2) Top N rows with maximum attribute value :
select name, value
from temm
where (
select count(*) from temm as n
where n.name = temm.name and n.attribute > temm.attribute
) < 1 ; /* 1 can be changed to 2,3,4 ..N to get N rows */