Check if number is already in field before concatenating? - java

I am writing a crawler that scans many urls and then puts all the words found in each webpage into a table. In this same table the ID of the url is stored. If the word is repeated in another page, the ID of the url the word was found on is concatenated with a comma separating them. So if a word appears on multiple pages, all the concatenated ID numbers in the field might look like:
2,3,6,8,9
At the moment, if the number appears multiple times on the same page, the ID number will be added each time the number is found so the URLID field might end up looking like:
2,2,2,4,7,8,8,8,8,8,9,9
Using Java is there a way I get it to check if the number exists in the field already and only add it if it is not already there? I have looked through the api but cannot seem to find a suitable way to do this. Any ideas?
Addition:
public void updateWordTable( String[] array, int urlid ) throws SQLException, IOException {
Statement stat = connection.createStatement();
String wordQuery;
String query;
for (String item : array) {
if(item.matches("[A-Za-z0-9]+")){
wordQuery = "SELECT * FROM word WHERE word = '"+item+"'";
ResultSet rs = stat.executeQuery(wordQuery);
if(!rs.next()){
query = "INSERT INTO word VALUES ('"+item+"',"+urlid+")";
stat.executeUpdate( query );
}
else {
//query = "UPDATE word SET urlid = concat(urlid, ',"+urlid+"') WHERE word = '"+item+"' ";
//query = "UPDATE word SET urlid = CASE WHEN FIND_IN_SET( '"+urlid+"', urlid ) > 0 THEN urlid ELSE CONCAT( urlid, ',', '"+urlid+"' )END WHERE word = '"+item+"' ";
String query2 = "UPDATE word SET urlid = CASE WHEN FIND_IN_SET( ?, urlid ) > 0 THEN urlid ELSE CONCAT( urlid, ',', ? )END WHERE word = ? ";
PreparedStatement pst = connection.prepareStatement( query2 );
pst.setLong( 1, urlid );
pst.setLong( 2, urlid );
pst.setString( 3, item);
int result = pst.executeUpdate();
//stat.executeUpdate( query2 );
}
}
}
stat.close();
}

... is there a way I get it to check if the number exists in the field already and only add it if it is not already there?
You can do it using JAVA, but leave that checking to MySQL as it has such search features.
Using MySQL, you can use FIND_IN_SET function on comma separated values in the column. This will solve your problem to not reprocess in JAVA to find if such id exists.
select
FIND_IN_SET( value_to_find, column_with_cs_values ) > 0 as bool_matched
from table_name
Add where condition and others if any required.
And in the JAVA code you can just read the resultset for getBoolean.
boolean idMatched = rs.getBoolean( "bool_matched" );
if( idMatched ) {
// dont update table
}
else {
// update table
}
Alternatively, you can directly update the table column.
Example:
UPDATE table_name
SET column_name_with_cs_values =
CASE WHEN FIND_IN_SET( value_to_find,
column_name_with_cs_values
) > 0 THEN column_name_with_cs_values
ELSE CONCAT( column_name_with_cs_values, ',', value_to_find )
END
-- add where etc here
;
In JAVA, you can use the above query like the following with PreparedStatement.
String query = "UPDATE word
SET urlid = CASE WHEN FIND_IN_SET( ?, urlid ) > 0 THEN urlid
ELSE CONCAT( urlid, ',', ? )
END
WHERE word = ? ";
PreparedStatement pst = con.prepareStatement( query );
pst.setString( 1, urlid );
pst.setString( 2, urlid );
pst.setString( 3, item);
int result = pst.executeUpdate();

I guess your values are stored in mysql because your question is tagged mysql. In java you can request your database with a select and check if the value is already inserted.
Or if your are not in the mysql world but only java, use a structure that give you the guartantee of unicity as a Set instead of a List.

The easiest way would be just to load those values into Set. Set will take case to have unique elements only.
The idea is whenever you store your IDs this structure should keep uniqueness. Set is the best one when we talk about Java.
If you would like to have some mechanism on database to provide uniqueness that's another story.
That's just the general tip.

If your field is a String then you can use regex
boolean exists = s.matches("(^|.*,)"+ n + "($|,.*)");

Step1: Store new url_id in temp variable.
Step2: now check this url_id existence in your table by select statement, you can do this by below query, suppose new url_id is 7:
SELECT COUNT(url_id) FROM mytable WHERE (url_id LIKE '7,%' OR url_id LIKE '%,7' OR url_id LIKE '%,7,%');
Step3: if you get any count from above query then leave it, otherwise add in your table.

I was having a project coded in pl/sql that comes across the case like yours. My variable is stored in a String and I have to check if the number was already in the String variable. I did it from using
IF instr('2,3,6,8,9,' '2,') <= 0 THEN
' Code to append the '2,'
End If
For JAVA there is something similar to instr method, String.indexOf()
http://www.tutorialspoint.com/java/java_string_indexof.htm
However note that it will return 0 if it's the first character, so probably it will be < 0
String a = "2,3,6,8,9,";
If a.indexOf(ID + ",") < 0 { // -1 equivalent to NOT FOUND
// code to append ID + ",";
}
Note I need to check on ID + "," reason is e.g.
ID = "2";
a = "20,3,6,8,9,";
It will return me 0 due to the 20. Therefore I'm using comma as a delimiter for every number found.
So after I finish append variable a, I would remove the last comma by
a = a.substring(0, a.length()-1); // this will remove the last ","
System.out.println(a); // the output should be - 2,3,6,8,9
This is using Java if your variable is stored in Java.

Related

Java dynamically generate SQL query - ATHENA

I am trying to generate sql query based on user input. There are 4 search fields on the UI:
FIRST_NAME, LAST_NAME, SUBJECT, MARKS
Based on user input I am planning to generate SQL query. Input can be of any combination.
eg: select * from TABLE where FIRST_NAME="some_value";
This query needs to be generated when FIRST_NAME is given and other fields are null
select * from TABLE where FIRST_NAME="some_value" and LAST_NAME="some_value";
This query needs to be generated when FIRST_NAME and LAST_NAME are given and other fields are null
Since there are 4 input fields, number of possible queries that can be generated are 24 (factorial of 4).
One idea is to write if condition for all 24 cases.
Java pseudo code:
String QUERY = "select * from TABLE where ";
if (FIRST_NAME!=null) {
QUERY = QUERY + "FIRST_NAME='use_input_value';"
}
if (LAST_NAME!=null) {
QUERY = QUERY + "LAST_NAME='use_input_value';"
}
if (SUBJECT!=null) {
QUERY = QUERY + "SUBJECT='use_input_value';"
}
if (MARKS!=null) {
QUERY = QUERY + "MARKS='use_input_value';"
}
I am not able to figure out how to generate SQL queries with AND coditions for multiple Input values.
I have been through concepts on dynamically generate sql query but couldn't process further.
Can someone help me on this.
FYI: I have been through How to dynamically generate SQL query based on user's selections?, still not able to generate query string based on user input.
Let's think about what would happen if you just ran the code you wrote and both FIRST_NAME and LAST_NAME are provided. You'll wind up with this:
select * from TABLE where FIRST_NAME='use_input_value';LAST_NAME='use_input_value';
There are two problems here:
The query is syntactically incorrect.
It contains the literals 'use_input_value' instead of the values you want.
To fix the first problem, let's first add and to the start of each expression, and remove the semicolons, something like this:
String QUERY = "select * from TABLE where";
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME='use_input_value'";
}
Notice the space before the and. We can also remove the space after where.
Now the query with both FIRST_NAME and LAST_NAME will look like this:
select * from TABLE where and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value'
Better but now there's an extra and. We can fix that by adding a dummy always-true condition at the start of the query:
String QUERY = "select * from TABLE where 1=1";
Then we append a semicolon after all the conditions have been evaluated, and we have a valid query:
select * from TABLE where 1=1 and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value';
(It may not be necessary to append the semicolon. Most databases don't require semicolons at the end of a single query like this.)
On to the string literals. You should add a placeholder instead, and simultaneously add the value you want to use to a List.
String QUERY = "select * from TABLE where";
List<String> args = new ArrayList<>();
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME=?";
args.add(FIRST_NAME);
}
After you've handled all the conditions you'll have a string with N '?' placeholders and a List with N values. At that point just prepare a query from the SQL string and add the placeholders.
PreparedStatement statement = conn.prepareStatement(QUERY);
for (int i = 0; i < args.size(); i++) {
statement.setString(i + 1, args[i]);
}
For some reason columns and parameters are indexed starting at 1 in the JDBC API, so we have to add 1 to i to produce the parameter index.
Then execute the PreparedStatement.

How to prevent SQL injection when the statement has a dynamic table name?

I am having code something like this.
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
Calculation of fullTableName is something like:
public String getFullTableName(final String table) {
if (this.schemaDB != null) {
return this.schemaDB + "." + table;
}
return table;
}
Here schemaDB is the name of the environment(which can be changed over time) and table is the table name(which will be fixed).
Value for schemaDB is coming from an XML file which makes the query vulnerable to SQL injection.
Query: I am not sure how the table name can be used as a prepared statement(like the name used in this example), which is the 100% security measure against SQL injection.
Could anyone please suggest me, what could be the possible approach to deal with this?
Note: We can be migrated to DB2 in future so the solution should compatible with both Oracle and DB2(and if possible database independent).
JDBC, sort of unfortunately, does not allow you to make the table name a bound variable inside statements. (It has its reasons for this).
So you can not write, or achieve this kind of functionnality :
connection.prepareStatement("SELECT * FROM ? where id=?", "TUSERS", 123);
And have TUSER be bound to the table name of the statement.
Therefore, your only safe way forward is to validate the user input. The safest way, though, is not to validate it and allow user-input go through the DB, because from a security point of view, you can always count on a user being smarter than your validation.
Never trust a dynamic, user generated String, concatenated inside your statement.
So what is a safe validation pattern ?
Pattern 1 : prebuild safe queries
1) Create all your valid statements once and for all, in code.
Map<String, String> statementByTableName = new HashMap<>();
statementByTableName.put("table_1", "DELETE FROM table_1 where name= ?");
statementByTableName.put("table_2", "DELETE FROM table_2 where name= ?");
If need be, this creation itself can be made dynamic, with a select * from ALL_TABLES; statement. ALL_TABLES will return all the tables your SQL user has access to, and you can also get the table name, and schema name from this.
2) Select the statement inside the map
String unsafeUserContent = ...
String safeStatement = statementByTableName.get(usafeUserContent);
conn.prepareStatement(safeStatement, name);
See how the unsafeUserContent variable never reaches the DB.
3) Make some kind of policy, or unit test, that checks that all you statementByTableName are valid against your schemas for future evolutions of it, and that no table is missing.
Pattern 2 : double check
You can 1) validate that the user input is indeed a table name, using an injection free query (I'm typing pseudo sql code here, you'd have to adapt it to make it work cause I have no Oracle instance to actually check it works) :
select * FROM
(select schema_name || '.' || table_name as fullName FROM all_tables)
WHERE fullName = ?
And bind your fullName as a prepared statement variable here. If you have a result, then it is a valid table name. Then you can use this result to build a safe query.
Pattern 3
It's sort of a mix between 1 and 2.
You create a table that is named, e.g., "TABLES_ALLOWED_FOR_DELETION", and you statically populate it with all tables that are fit for deletion.
Then you make your validation step be
conn.prepareStatement(SELECT safe_table_name FROM TABLES_ALLOWED_FOR_DELETION WHERE table_name = ?", unsafeDynamicString);
If this has a result, then you execute the safe_table_name. For extra safety, this table should not be writable by the standard application user.
I somehow feel the first pattern is better.
You can avoid attack by checking your table name using regular expression:
if (fullTableName.matches("[_a-zA-Z0-9\\.]+")) {
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
}
It's impossible to inject SQL using such a restricted set of characters.
Also, we can escape any quotes from table name, and safely add it to our query:
fullTableName = StringEscapeUtils.escapeSql(fullTableName);
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
StringEscapeUtils comes with Apache's commons-lang library.
I think that the best approach is to create a set of possible table names and check for existance in this set before creating query.
Set<String> validTables=.... // prepare this set yourself
if(validTables.contains(fullTableName))
{
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
//and so on
}else{
// ooooh you nasty haker!
}
create table MYTAB(n number);
insert into MYTAB values(10);
commit;
select * from mytab;
N
10
create table TABS2DEL(tname varchar2(32));
insert into TABS2DEL values('MYTAB');
commit;
select * from TABS2DEL;
TNAME
MYTAB
create or replace procedure deltab(v in varchar2)
is
LvSQL varchar2(32767);
LvChk number;
begin
LvChk := 0;
begin
select count(1)
into LvChk
from TABS2DEL
where tname = v;
if LvChk = 0 then
raise_application_error(-20001, 'Input table name '||v||' is not a valid table name');
end if;
exception when others
then raise;
end;
LvSQL := 'delete from '||v||' where n = 10';
execute immediate LvSQL;
commit;
end deltab;
begin
deltab('MYTAB');
end;
select * from mytab;
no rows found
begin
deltab('InvalidTableName');
end;
ORA-20001: Input table name InvalidTableName is not a valid table name ORA-06512: at "SQL_PHOYNSAMOMWLFRCCFWUMTBQWC.DELTAB", line 21
ORA-06512: at "SQL_PHOYNSAMOMWLFRCCFWUMTBQWC.DELTAB", line 16
ORA-06512: at line 2
ORA-06512: at "SYS.DBMS_SQL", line 1721

Retrieve database in java using JTextField to search

So, i would like to retrieve database information where a user will search certain columns using text fields, like this:
column1 find userinput,
column2 find userinput,
column3 find userinput,
The problem im having is the sql statement:
String sql = "select * from table where column = '" + textfield1.getText() + "'";
If textfield1 is empty, it will only retrieve entries that contain nothing.
What im trying to retrieve will have 6 text field, meaning 6 columns in the database. Using java i would need alot of if statements.
Is there any other way to shorten this?
EDIT
-- MORE INFO --
The if statements will start from:
if (!(t1.getText().equals("")) && !(t2.getText().equals("")) && !(t3.getText().equals(""))
&& !(t4.getText().equals("")) && !(t5.getText().equals("")) && (t6.getText().equals("")))
all the way down to
if (t1.getText().equals("") && t2.getText().equals("") && t3.getText().equals("")
&& t4.getText().equals("") && t5.getText().equals("") && t6.getText().equals("")
covering all possible combinations of the 6 input fields, the point of all these statements is to ignore empty text fields but provide the corresponding sql statement.
I don't know how to calculate the possible combinations other than writing them all down(i started, there was too many).
I didn't really understand why those ifs, you should elaborate more your question but i will try to help as i can.
Well, if you want to retrieve everything from the database you could use LIKE:
String sql = "select * from table where column like '%" + textfield1.getText() + "%'";
This way you'll get everything with the containing text, it means, if the field is empty it will bring all results, i guess this is the best way to do, to avoid unnecessa if clauses.
Another thing, to check for empty fields you should use:
t1.getText().trim().isEmpty()
BUT if you let they write white spaces the LIKE won't help you then you need to .trim() all your texts then your white spaces will be ignored.
The following can be formulated much neater, but to make the point:
JTextField ts = new JTextField[6];
Set<String> values = new HashSet<>(); // Removes duplicates too.
for (JTextField t : ts) {
String text = ts.getText().trim();
if (!text.isEmpty()) {
values.add(text);
}
}
// Build the WHERE condition of a PreparedStatement
String condition = "";
for (String value : values) {
condition += condition.isEmpty() ? "WHERE" : " OR";
condition += " column = ?";
}
String sql = "select * from table " + condition;
PreparedStatement stm = connection.prepareStatement(sql);
int index = 1; // SQL counts from 1
for (String value : values) {
stm.setString(index, value);
++index;
}
ResultSet rs = stm.executeQuery();
The usage of a PreparedStatement makes escaping ' (and backslash and such) no longer needed and also prevents SQL injection (see wikipedia).
i have a problem i want to search data based on multiple jtext fields where did i go wrong coz this displays only one row which has the first id
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String sql="SELECT Employee.EmpID,Employee.Fname,Employee.Mname,Employee.Sname,Employee.DoB,Employee.Phone,"
+ "Employee.Email,Employee.Nationality,Employee.Desegnition,Employee.NSSF,Employee.WCF,"
+ "Employee.BSalary,Allowance.medical,Allowance.Bonus,Allowance.others,Allowance.tov,Allowance.TA,"
+ "Attendece.Hrs from Employee,Allowance,Attendece WHERE "
+ "Employee.EmpID=Allowance.EmpID and Attendece.EmpID=Allowance.EmpID AND Employee.EmpID=? AND Attendece.Dt=?";
try{
pd=conn.prepareStatement(sql);
pd.setString(1,id.getText());
pd.setString(2,Date1.getText());
r=pd.executeQuery();
//setting the text fields
if(r.next())
{
String a=r.getString("EmpID");
eid.setText(a);
String b=r.getString("Fname");
fname.setText(b);
String c=r.getString("Mname");
mname.setText(c);
String d=r.getString("Sname");
sname.setText(d);
String e=r.getString("DoB");
dob.setText(e);
String f=r.getString("Desegnition");
Des.setText(f);
String g=r.getString("Bsalary");
bsal.setText(g);
String h=r.getString("Phone");
phone.setText(h);
String i=r.getString("Email");
email.setText(i);
String j=r.getString("Nationality");
nationality.setText(j);
String k=r.getString("Desegnition");
Des.setText(k);
String l=r.getString("NSSf");
nssf.setText(l);
String m=r.getString("WCF");
wcf.setText(m);
String n=r.getString("tov");
oh.setText(n);
String o=r.getString("Bonus");
bn.setText(o);
String p=r.getString("medical");
md.setText(p);
String q=r.getString("others");
ot.setText(q);
String s=r.getString("TA");
ta.setText(s);
String t=r.getString("Hrs");
hrs.setText(t);
int day;
day=Integer.parseInt(t)/8;
days.setText(Integer.toString(day));
double week=day/7;
weeks.setText(Double.toString(week));
}
r.close();
pd.close();
}catch(Exception e)
{
}

Error: Before start of result set in Java

I know this would be a foolish question to ask but still i need to do this.
This is a basic program in java application where I want to use 3 queries simultaneously to print the table.
(I'm not using any Primary key in this case so please help me to resolve this without making my attributes as primary keys - I know this is not a good practice but for now i need to complete it.)
my code:
Connection con = null;
Statement stat1 = null, stat2 = null, stat3 = null;
ResultSet rs1, rs2, rs3;
stat1 = con.createStatement();
stat2 = con.createStatement();
stat3 = con.createStatement();
String str = "\nProduct\tC.P\tS.P.\tStock\tExpenditure\tSales";
info.setText(str);
String s1 = "SELECT type, cp, sp, stock FROM ts_items GROUP BY type ORDER BY type";
String s2 = "SELECT expenditure FROM ts_expenditure GROUP BY type ORDER BY type";
String s3 = "SELECT sales FROM ts_sales GROUP BY type ORDER BY type";
rs1 = stat1.executeQuery(s1);
rs2 = stat2.executeQuery(s2);
rs3 = stat3.executeQuery(s3);
String type;
int cp, sp, stock, expenditure, sales;
while( rs1.next() || rs2.next() || rs3.next() )
{
type = rs1.getString("type");
cp = rs1.getInt("cp");
sp = rs1.getInt("sp");
stock = rs1.getInt("stock");
expenditure = rs2.getInt("expenditure");
sales = rs3.getInt("sales");
info.append("\n" + type + "\t" + cp + "\t" + sp + "\t" + stock + "\t" + expenditure + "\t" + sales);
}
Output:
Runtime Exception: Before start of result set
This is the problem:
while( rs1.next() || rs2.next() || rs3.next() )
If rs1.next() returns true, rs2.next() and rs3.next() won't be called due to short-circuiting. So rs2 and rs3 will both be before the first row. And if rs1.next() returns false, then you couldn't read from that anyway...
I suspect you actually want:
while (rs1.next() && rs2.next() && rs3.next())
After all, you only want to keep going while all three result sets have more information, right?
It's not clear why you're not doing an appropriate join, to be honest. That would make a lot more sense to me... Then you wouldn't be trying to use multiple result sets on a single connection, and you wouldn't be relying on there being the exact same type values in all the different tables.
You do an OR so imagine only one ResultSet has a result.
What you end up with is trying to read from empty result sets.
Suppose rs1 has one result and rs3 has 3 results. Now as per your code it will fail for rs1.getString("type"); during second iteration.
Better to loop over each resultSet separately.
This is going to go badly wrong, in the event that there is a type value that's missing from one of your three tables. Your code just assumes you'll get all of the types from all of the tables. It may be the case for your current data set, but it means that your code is not at all robust.
I would seriously recommend having just one SQL statement, that has each of your three selects as subselects, then joins them all together. Your java can just iterate over the result from this one SQL statement.

Execute "sp_msforeachdb" in a Java application

Hi StackOverflow community :)
I come to you to share one of my problems...
I have to extract a list of every table in each database of a SQL Server instance, I found this query :
EXEC sp_msforeachdb 'Use ?; SELECT DB_NAME() AS DB, * FROM sys.tables'
It works perfectly on Microsoft SQL Server Management Studio but when I try to execute it in my Java program (that includes JDBC drivers for SQL Server) it says that it doesn't return any result.
My Java code is the following :
this.statement = this.connect.createStatement(); // Create the statement
this.resultats = this.statement.executeQuery("EXEC sp_msforeachdb 'Use ?; SELECT DB_NAME() AS DB, * FROM sys.tables'"); // Execute the query and store results in a ResultSet
this.sortie.ecrireResultats(this.statement.getResultSet()); // Write the ResultSet to a file
Thanks to anybody who will try to help me,
Have a nice day :)
EDIT 1 :
I'm not sure that the JDBC driver for SQL Server supports my query so I'll try to get to my goal in another way.
What I'm trying to get is a list of all the tables for each database on a SQL Server instance, the output format will be the following :
+-----------+--------+
| Databases | Tables |
+-----------+--------+
So now I'm asking can someone help me to get to that solution using SQL queries thru Java's JDBC for SQL Server driver.
I also wish to thanks the very quick answers I got from Tim Lehner and Mark Rotteveel.
If a statement can return no or multiple results, you should not use executeQuery, but execute() instead, this method returns a boolean indicating the type of the first result:
true: result is a ResultSet
false : result is an update count
If the result is true, then you use getResultSet() to retrieve the ResultSet, otherwise getUpdateCount() to retrieve the update count. If the update count is -1 it means there are no more results. Note that the update count will also be -1 when the current result is a ResultSet. It is also good to know that getResultSet() should return null if there are no more results or if the result is an update count.
Now if you want to retrieve more results, you call getMoreResults() (or its brother accepting an int parameter). The return value of boolean has the same meaning as that of execute(), so false does not mean there are no more results!
There are only no more results if the getMoreResults() returns false and getUpdateCount() returns -1 (as also documented in the Javadoc)
Essentially this means that if you want to correctly process all results you need to do something like below:
boolean result = stmt.execute(...);
while(true)
if (result) {
ResultSet rs = stmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = stmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = stmt.getMoreResults();
}
NOTE: Part of this answer is based on my answer to Java SQL: Statement.hasResultSet()?
If you're not getting an error, one issue might be that sp_msforeachdb will return a separate result set for each database rather than one set with all records. That being the case, you might try a bit of dynamic SQL to union-up all of your rows:
-- Use sys.tables
declare #sql nvarchar(max)
select #sql = coalesce(#sql + ' union all ', '') + 'select ''' + quotename(name) + ''' as database_name, * from ' + quotename(name) + '.sys.tables'
from sys.databases
select #sql = #sql + ' order by database_name, name'
exec sp_executesql #sql
I still sometimes use INFORMATION_SCHEMA views as well, since it's easier to see the schema name, among other things:
-- Use INFORMATION_SCHEMA.TABLES to easily get schema name
declare #sql nvarchar(max)
select #sql = coalesce(#sql + ' union all ', '') + 'select * from ' + quotename(name) + '.INFORMATION_SCHEMA.TABLES where TABLE_TYPE = ''BASE TABLE'''
from sys.databases
select #sql = #sql + ' order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME'
exec sp_executesql #sql
Be aware that this method of string concatenation (select #sql = foo from bar) may not work as you intend through a linked server (it will only grab the last record). Just a small caveat.
UPDATE
I've found the solution !
After reading an article about sp_spaceused being used with Java, I figured out that I was in the same case.
My final code is the following :
this.instances = instances;
for(int i = 0 ; i < this.instances.size() ; i++)
{
try
{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
this.connect = DriverManager.getConnection("jdbc:sqlserver://" + this.instances.get(i), "tluser", "result");
this.statement = this.connect.prepareCall("{call sp_msforeachdb(?)}");
this.statement.setString(1, "Use ?; SELECT DB_NAME() AS DB, name FROM sys.tables WHERE DB_NAME() NOT IN('master', 'model', 'msdb', 'tempdb')");
this.resultats = this.statement.execute();
while(true)
{
int rowCount = this.statement.getUpdateCount();
if(rowCount > 0)
{
this.statement.getMoreResults();
continue;
}
if(rowCount == 0)
{
this.statement.getMoreResults();
continue;
}
ResultSet rs = this.statement.getResultSet();
if(rs != null)
{
while (rs.next())
{
this.sortie.ecrireResultats(rs); // Write the results to a file
}
rs.close();
this.statement.getMoreResults();
continue;
}
break;
}
this.statement.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
It tried it out and my file has everything I want in it.
Thank you all for your help ! :)

Categories