how can i have batch read a list of user names and use those in an sql statement?

Go To StackoverFlow.com

4

Currently I have the following batch code to read 1 user name, and use it in sql

@echo on
cls
set userID=
for /F %%i in (UserID.txt) do set userID=%userID% %%i
sqlcmd -S server -d database -U username -P password -v userID=%userID% 
                -i "sqlQuery.sql" -s "," > "\output.csv" -I -W -k

The SQL query that is called is as follows

SELECT userId, COUNT (*) AS number 
FROM table 
WHERE userId = '$(userID)' 
GROUP BY userId 
ORDER BY userId desc

What I am looking for is if I have a list of user names in the text file it will dynamically change the WHERE statement to be

WHERE userId = '$(userID1)' OR userId = '$(userID2)' etc....
2012-04-05 16:56
by mhopkins321
This would probably be a lot more feasible if you were to switch from a batch script to Powershell.. - Michael Fredrickson 2012-04-05 17:05
bummer. I have never worked with powershell before :- - mhopkins321 2012-04-05 17:07
I think your major limitation would be that with loops they are separate echo commands which means new lines in the output file... I'm not familiar with sql script, but if it can take multiple lines enclosed in ( ) it should work - iesou 2012-04-05 18:43
what sql version - Mark Schultheiss 2012-04-05 19:09
@MichaelFredrickson - This is actually a simple problem to solve with batch. See my answer. I'm sure it is equally simple with Powershell, as well as any number of other languages - dbenham 2012-04-05 21:26


5

I haven't worked much with SQL scripts so I'm not sure if returns will cause a problem but this will generate what you need.

I used this input in a file called userID.txt:

steve,joe,fred,jason,bill,luke

ran it through this code:

@echo off
setlocal enabledelayedexpansion
set count=0
for /F "tokens=* delims=," %%G in (userID.txt) do call :loop %%G
:loop
if "%1"=="" goto :endloop
set /a count+=1
set userid%count%=%1
SHIFT
goto :loop
:endloop
set totalusers=%count%
set /a totalusers-=1

echo SELECT userId, COUNT (*) AS number FROM table WHERE ( > sqlQuery.sql
set count=0
:where_gen_loop
set /a count+=1
if !count! gtr !totalusers! goto endwhere_gen_loop
echo userId = '$(!userid%count%!)' OR>> sqlQuery.sql
goto where_gen_loop
:endwhere_gen_loop
echo userId = '$(!userid%count%!)'>> sqlQuery.sql
echo ) >> sqlQuery.sql
echo GROUP BY userId ORDER BY userID desc >> sqlQuery.sql

that generated this output in sqlQuery.sql:

SELECT userId, COUNT (*) AS number FROM table WHERE ( 
userId = '$(steve)' OR
userId = '$(joe)' OR
userId = '$(fred)' OR
userId = '$(jason)' OR
userId = '$(bill)' OR
userId = '$(luke)'
) 
GROUP BY userId ORDER BY userID desc 

and is then accessed by the end of the batch:

sqlcmd -S server -d database -U username -P password -i "sqlQuery.sql" -s "," > "\output.csv" -I -W -k

endlocal
2012-04-05 18:28
by iesou
+1 I'm always impressed when I see people acheive real results with Windows Batch files. It proves its possible but I still have difficulty beleiving it : - Karl 2012-04-05 19:40
Thanks! I think I troll the batch questions more than others just for the challenge factor... plus I think if you can use a batch to accomplish something instead of vbs etc... it means it can work in more environments. Always a plus - iesou 2012-04-05 19:50
There are a number of problems with this answer: 1) The SQL query is wrong - it will look for variables named steve, joe, etc. 2) I believe the input text file has the wrong structure - the original question implies one userID per line. 3) Bad practice to let the code fall into the subroutine. If the batch is called with an argument, then could get failure. 4) It is much more complicated than is needed - dbenham 2012-04-05 20:35
Haha, well thank you for your response. Like I said... I don't know much about .sql script I just did what he wanted based on what he asked for: What I am looking for is if I have a list of user names in the text file it will dynamically change the WHERE statement to be: WHERE userId = '$(userID1)' OR userId = '$(userID2)' etc....iesou 2012-04-05 20:42
fantastic, thanks a bunc - mhopkins321 2012-04-06 14:54


4

All you need to do is modify your sql query to use an IN clause, and then format your variable properly. You also must use delayed expansion within the FOR loop because %userID% is expanded only once when the FOR statement is parsed, whereas !userID! is expanded at execution time for each loop iteration.

sqlQuery.sql:

SELECT userId, 
       COUNT(*) AS number
  FROM table
 WHERE userId in( $(userID) )
 GROUP BY userId
 ORDER BY userId desc

batch script:

@echo on
setlocal enableDelayedExpansion
set userID=
for /f %%i in (UserID.txt) do set "userID=!userID!,'%%i'"
sqlcmd -S server -d database -U username -P password -v userID="%userID:~1%" -i "sqlQuery.sql" -s "," > "\output.csv" -I -W -k

Note that the sql variable definition is using a batch substring operation to eliminate the leading comma.

The userID variable will end up looking something like 'userID1','userID2','userID3'

If there are too many IDs in the input file to fit within the ~8k environment variable limit, then you will need to dynamically build your sql script. At that point, you might as well eliminate the sql variables and simply use string literals.

@echo on
setlocal enableDelayedExpansion
set "delim="
>"sqlQuery.sql" echo SELECT userId, COUNT(*) AS number FROM table WHERE userId in(
for /f %%i in (UserID.txt) do (
  >>"sqlQuery.sql" echo !delim!'%%i'
  set "delim=,"
)
>>"sqlQuery.sql" echo ) GROUP BY userId ORDER BY userId desc
sqlcmd -S server -d database -U username -P password -i "sqlQuery.sql" -s "," > "\output.csv" -I -W -k
2012-04-05 20:12
by dbenham
+1... You made it look a lot simpler than I thought it would be in a batch script.. - Michael Fredrickson 2012-04-05 21:52
cool thanks so much - mhopkins321 2012-04-06 14:54
Ads