Optimize code block for LINQ and non LINQ
First - if you are working with DataTables, then you can use Linq to DataSet, which has nice extension methods to get field values.

Now let's review logic of your code. You are not using any data from tblone and tbltwo in your result. Actually you only finding joined categories between these two tables, and for each matched rows pair you are adding all m values from tblthree and tblfour to result. I find this logic pretty strange. Maybe you are expecting only single match here. Then you will need boolean result (match found or not). But basically you need count of joined rows:

var matchedCategoriesCount = 
            (from one in tblone.AsEnumerable().Where(r =&gt; r.Field&lt;bool&gt;("id"))
             join two in tbltwo.AsEnumerable()
                on one.Field&lt;string&gt;("cate") equals two.Field&lt;string&gt;("category")
             select one).Count();


Same with lambda syntax if you find it more readable:

var matchedCategoriesCount = 
            tblone.AsEnumerable().Where(r =&gt; r.Field&lt;bool&gt;("id"))
                  .Join(tbltwo.AsEnumerable(),
                        one =&gt; one.Field&lt;string&gt;("cate"),
                        two =&gt; two.Field&lt;string&gt;("category"),
                        (one, two) =&gt; one)
                  .Count();


Then you can select m values from tblthree and tblfour N times and create new DataTable:

// if (matchedCategoriesCount &gt; 0)
var values = tblthree.AsEnumerable().Concat(tblfour.AsEnumerable())
                     .Select(r =&gt; r.Field&lt;string&gt;("m")))
                     .ToArray();


You can even use simple loop here:

for(int i = 0; i &lt; matchedCategoriesCount; i++)
   foreach(var value in values)
       datatemp.Rows.Add(value);


And last - don't use variable names like tblone, tbltwo, tblthree etc. These names does not explain what data these variables hold. Use names from domain of your application.