Generate a sorted report in Access - database

I want to generate a report in Access that depends on a parameter.
Let's say my table looks something like this:
id usr password last_seen workplace
01 test1 12345 -- M
02 test2 12345 -- G
03 test3 12345 -- M
04 test4 12345 -- H
... ... ... ... ...
(this is not my table, but for now assume it is).
Now I want to make a report where you can type in: "M" and it shows a list of people living in "M" (same for "Z", "G" and any other town).
How can I do this? I'm pretty new to Access so I really don't have an idea.
MS Access Version: 2010

Open the report query in design mode and provide a Where clause. The output is something similar to this,
Where WorkPlace = [WorkPlace]
Feel free to leave a message if you are encountering any issues.

Open the report with a filter.
In VBA:
Dim strWorkplace As String
' strWorkplace = "M"
' or interactively
strWorkplace = InputBox("Enter workplace")
' Prevent SQL injection
strWorkplace = Replace(strWorkplace, "'", "''")
DoCmd.OpenReport "YourReportName", WhereCondition:="workplace = '" & strWorkplace & "'"
For a numeric parameter, leave out the single quotes.

Related

SQL Server query success but no results

Using SQL Server Management Studo v 18.12.1 on a VDI with 64bit Windows Microsoft SQL Server 2019. This device has 96 GB of free space and also has free temporary space.
I loaded a new database and table which has 1,301,902 rows from a csv with no errors using the Data import tool. I have used this on several other tables in this server with no problem.
I run a query like this
set rowcount 10
select xyz.["PPI"],xyz.["Business Mailing Address One"]
from [DBNAME].[dbo].[table_name] xyz
and this returns:
"PPI" "Business Mailing Address One"
"7251" "2100 S TRAVIS DR"
"1346" "392 HAWKINS ST"
"1351" "PO BOX 81001-0798"
"0289" "123 E MAIN ST"
"4022" "2890 KLAMATH FALLS BLVD"
"19118" "3639 E FALLS DR"
"8421" "" ""
"45800" "" ""
"6507" "" ""
"1112" "" ""
Then run this query
set rowcount 0
select xyz.["PPI"],xyz.["Business Mailing Address One"]
from [DBNAME].[dbo].[table_name] xyz
where xyz.["Business Mailing Address One"] like 'PO%'
This returns:
"PPI" "Business Mailing Address One"
zero rows... Query executed successfully
Using = 'PO%' has the same result
Also copied the response into the where statement like
where xyz.["Business Mailing Address One"] = 'PO BOX 81001-0798'
and also get the same result
Taking your data exactly how it is, and assuming that all values appear in the dataset are surrounded with quotes, you would need to ensure your fuzzy search also starts with a quote.
DECLARE #Data AS TABLE(
["PPI"] VARCHAR(10),
["Business Mailing Address One"] NVARCHAR(50)
)
INSERT INTO #Data VALUES
('"7251"', '"2100 S TRAVIS DR"') ,
('"1346"', '"392 HAWKINS ST"'),
('"1351"', '"PO BOX 81001-0798"'),
('"0289"', '"123 E MAIN ST"'),
('"4022"', '"2890 KLAMATH FALLS BLVD"'),
('"19118"', '"3639 E FALLS DR"'),
('"8421"', '" "'),
('"45800"', '" "'),
('"6507"', '" "'),
('"1112"', '" "')
SELECT xyz.["PPI"], xyz.["Business Mailing Address One"]
FROM #Data xyz
WHERE xyz.["Business Mailing Address One"] like '"PO%'

Command button to look up and match data from a query to a table

Can someone assist me with a VBA code that does the following?
Given query "Query1" and Table "Table1" in an Access DB
I would like to create a command button to loop through Query1, lookup and match a field.
Lookup [Query1].[number]=[Table1].[number]
set [Table1].[length]=[Query1].[Tlength]
For all the numbers in Query1
Not all numbers in Table1 exist in Query1
(I currently have the table1 fields in a form, if I made this operation in a query, I would not be able to add a new number entry in the form, that is why I would like to create macro command button on the form to update a length field in the table)
So when the command button is pressed table1 Tlength would be updated as such:
Query1:
Number | Length
N001 | 120
N005 | 60
N006 | 50
ect.
Table1:
Number | Tlength
N001 | 120
N002 |
N003 |
N005 | 60
N006 | 50
ect.
This can be achieved with a quite simple update query.
If Query1 is an updateable query, we can use an INNER JOIN to construct our update query:
UPDATE Table1 INNER JOIN Query1 ON Table1.[Number] = Query1.[Number]
SET Table1.TLength = Query1.[Length]
However, if Query1 is not updateable, we will need to use a DLookUp:
UPDATE Table1
SET Table1.TLength = DLookUp("Length", "Query1", "[Number] = '" & [Number] & "'")
You can easily execute the SQL on a button click using either a macro or VBA.
I ran it with the following code given that my Table1 is "Wire_Designation" with Number and Length and and Query1 is Total_Length_Query with Number and Tlength. When I run it, it works. However, if I try to save the database thereafter, the database gives me an error that I don't have exclusive access to the database, and I would have to close and reopen the database. Does anyone know the reason?
Dim MyRst As DAO.Recordset
Dim MyRst As Recordset
Set MyRst = CurrentDb.OpenRecordset("Wire_Designation")
MyRst.MoveFirst
Do Until MyRst.EOF
MyRst.Edit
MyRst![Length] = DLookup("Tlength", "Total_Length_Query", "[Number] = '" &
MyRst![Number] & "'")
MyRst.Update
MyRst.MoveNext
Loop
MyRst.Close
Set MyRst = Nothing

RODBC::sqlSave - problems creating/appending to a table

Related to several other questions on the RODBC package, I'm having problems using RODBC::sqlSave to write to a table on a SQL Server database. I'm using MS SQL Server 2008 and 64-bit R on a Windows RDP.
The solution in the 3rd link (questions) does work [sqlSave(ch, df)]. But in this case, it writes to the wrong data base. That is, my default DB is "C2G" but I want to write to "BI_Sandbox". And it doesn't allow for options such as rownames, etc. So there still seems to be a problem in the package.
Obviously, a possible solution would be to change my ODBC solution to the specified database, but it seems there should be a better method. And this wouldn't solve the problem of unusable parameters in the sqlSave command--such as rownames, varTypes, etc.
I have the following ODBC- System DSN connnection:
Microsoft SQL Server Native Client Version 11.00.3000
Data Source Name: c2g
Data Source Description: c2g
Server: DC01-WIN-SQLEDW\BISQL01,29537
Use Integrated Security: Yes
Database: C2G
Language: (Default)
Data Encryption: No
Trust Server Certificate: No
Multiple Active Result Sets(MARS): No
Mirror Server:
Translate Character Data: Yes
Log Long Running Queries: No
Log Driver Statistics: No
Use Regional Settings: No
Use ANSI Quoted Identifiers: Yes
Use ANSI Null, Paddings and Warnings: Yes
R code:
R> ch <- odbcConnect("c2g")
R> sqlSave(ch, zinq_scores, tablename = "[bi_sandbox].[dbo].[table1]",
append= FALSE, rownames= FALSE, colnames= FALSE)
Error in sqlColumns(channel, tablename) :
‘[bi_sandbox].[dbo].[table1]’: table not found on channel
# after error, try again:
R> sqlDrop(ch, "[bi_sandbox].[dbo].[table1]", errors = FALSE)
R> sqlSave(ch, zinq_scores, tablename = "[bi_sandbox].[dbo].[table1]",
append= FALSE, rownames= FALSE, colnames= FALSE)
Error in sqlSave(ch, zinq_scores, tablename = "[bi_sandbox].[dbo].[table1]", :
42S01 2714 [Microsoft][SQL Server Native Client 11.0][SQL Server]There is already an object named 'table1' in the database.
[RODBC] ERROR: Could not SQLExecDirect 'CREATE TABLE [bi_sandbox].[dbo].[table1] ("credibility_review" float, "creditbuilder" float, "no_product" float, "duns" varchar(255), "pos_credrev" varchar(5), "pos_credbuild" varchar(5))'
In the past, I've gotten around this by running the supremely inefficient sqlQuery with insert into row-by-row to get around this. But I tried this time and no data was written. Although the sqlQuery statement did not have an error or warning message.
temp <-"INSERT INTO [bi_sandbox].[dbo].[table1]
+ (credibility_review, creditbuilder, no_product, duns, pos_credrev, pos_credbuild) VALUES ("
>
> for(i in 1:nrow(zinq_scores)) {
+ sqlQuery(ch, paste(temp, "'", zinq_scores[i, 1], "'",",", " ",
+ "'", zinq_scores[i, 2], "'", ",",
+ "'", zinq_scores[i, 3], "'", ",",
+ "'", zinq_scores[i, 4], "'", ",",
+ "'", zinq_scores[i, 5], "'", ",",
+ "'", zinq_scores[i, 6], "'", ")"))
+ }
> str(sqlQuery(ch, "select * from [bi_sandbox].[dbo].[table1]"))
'data.frame': 0 obs. of 6 variables:
$ credibility_review: chr
$ creditbuilder : chr
$ no_product : chr
$ duns : chr
$ pos_credrev : chr
$ pos_credbuild : chr
Any help would be greatly appreciated.
Also, if there is any missing detail, please let me know and I'll edit the question.
My apologies up front. This is not exactly a "simple example." It's pretty trivial, but there are a lot of parts. And by the end, you'll probably think I'm crazy for doing it this way.
Starting in SQL Server Management Studio
First, I've created a database on SQL Server called mtcars with default schema dbo. I've also added myself as a user. Under my own user name, I am the database owner, so I can do anything I want to the database, but from R, I will connect using a generic account that only has EXECUTE privileges.
The predefined table in the database that we are going to write to is called mtcars. (So the full path to the table is mtcars.dbo.mtcars; it's lazy, I know). The code to define the table is
USE [mtcars]
GO
/****** Object: Table [dbo].[mtcars] Script Date: 2/22/2016 11:56:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[mtcars](
[OID] [int] IDENTITY(1,1) NOT NULL,
[mpg] [numeric](18, 0) NULL,
[cyl] [numeric](18, 0) NULL,
[disp] [numeric](18, 0) NULL,
[hp] [numeric](18, 0) NULL
) ON [PRIMARY]
GO
Stored Procedures
I'm going to use two stored procedures. The first is an "UPSERT" procedure, that will first try to update a row in a table. If that fails, it will insert the row into the table.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.sample_procedure
#OID int = 0,
#mpg numeric(18,0) = 0,
#cyl numeric(18,0) = 0,
#disp numeric(18,0) = 0,
#hp numeric(18,0) = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- TRANSACTION code borrowed from
-- http://stackoverflow.com/a/21209131/1017276
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.mtcars
SET mpg = #mpg,
cyl = #cyl,
disp = #disp,
hp = #hp
WHERE OID = #OID;
IF ##ROWCOUNT = 0
BEGIN
INSERT dbo.mtcars (mpg, cyl, disp, hp)
VALUES (#mpg, #cyl, #disp, #hp)
END
COMMIT TRANSACTION;
END
GO
Another stored procedure I will use is just the equivalent of RODBC::sqlFetch. As far as I can tell, sqlFetch depends on SQL injection, and I'm not allowed to use it. Just to be on the safe side of our data security policies, I write little procedures like this (Data security is pretty tight here, you may or may not need this)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.get_mtcars
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT * FROM dbo.mtcars
END
GO
Now, from R
I have a utility function I use to help me manage inputting data into the stored procedures. sqlSave would do a lot of this automatically, so I'm kind of reinventing the wheel. The gist of the utility function is to determine if the value I'm pushing to the database needs to be nested in quotes or not.
#* Utility function. This does a couple helpful things like
#* Convert NA and NULL into a SQL NULL
#* wrap character strings and dates in single quotes
sqlNullString <- function(value, numeric=FALSE)
{
if (is.null(value)) value <- "NULL"
if (is.na(value)) value <- "NULL"
if (inherits(value, "Date")) value <- format(x = value, format = "%Y-%m-%d")
if (value == "NULL") return(value)
else if (numeric) return(value)
else return(paste0("'", value, "'"))
}
This next step isn't strictly necessary, but I'm going to do it just so that my R table is similar to my SQL table. This is organizational strategy on my part.
mtcars$OID <- NA
Now let's establish our connection:
server <- "[server_name]"
uid <- "[generic_user_name]"
pwd <- "[password]"
library(RODBC)
channel <- odbcDriverConnect(paste0("driver=SQL Server;",
"server=", server, ";",
"database=mtcars;",
"uid=", uid, ";",
"pwd=", pwd))
Now this next part is pure laziness. I'm going to use a for loop to push each row of the data frame the to SQL table one at a time. As noted in the original question, this is kind of inefficient. I'm sure I could write a stored procedure to accept several vectors of data, compile them into a temporary table, and do the UPSERT in SQL, but I don't work with large data sets when I'm doing this, and so it hasn't yet been worth it to me to write such a procedure. Instead, I prefer to stick with the code that is a little easier for me to reason with on my limited SQL skills.
Here, we're just going to push the first 5 rows of mtcars
#* Insert the first 5 rows into the SQL Table
for (i in 1:5)
{
sqlQuery(channel = channel,
query = paste0("EXECUTE dbo.sample_procedure ",
"#OID = ", sqlNullString(mtcars$OID[i]), ", ",
"#mpg = ", mtcars$mpg[i], ", ",
"#cyl = ", mtcars$cyl[i], ", ",
"#disp = ", mtcars$disp[i], ", ",
"#hp = ", mtcars$hp[i]))
}
And now we'll take a look at the table from SQL
sqlQuery(channel = channel,
query = "EXECUTE dbo.get_mtcars")
This next line is just to match up the OIDs in R and SQL for illustration purposes. Normally, I would do this manually.
mtcars$OID[1:5] <- 1:5
This next for loop will UPSERT all 32 rows. We already have 5, we're UPSERTing 32, and the SQL table at the end should have 32 if we've done it correctly. (That is, SQL will recognize the 5 rows that already exist)
#* Update/Insert (UPSERT) the entire table
for (i in 1:nrow(mtcars))
{
sqlQuery(channel = channel,
query = paste0("EXECUTE dbo.sample_procedure ",
"#OID = ", sqlNullString(mtcars$OID[i]), ", ",
"#mpg = ", mtcars$mpg[i], ", ",
"#cyl = ", mtcars$cyl[i], ", ",
"#disp = ", mtcars$disp[i], ", ",
"#hp = ", mtcars$hp[i]))
}
#* Notice that the first 5 rows were unchanged (though they would have changed
#* if we had changed the data...the point being that the stored procedure
#* correctly identified that these records already existed)
sqlQuery(channel = channel,
query = "EXECUTE dbo.get_mtcars")
Recap
The stored procedure approach has a major disadvantage in that it is blatantly reinventing the wheel. It also requires that you learn SQL. SQL is pretty easy to learn for simple tasks, but some of the code I've written for more complex tasks is pretty difficult to interpret. Some of my procedures have taken me the better part of a day to get right. (once they are done, however, they work incredibly well)
The other big disadvantage to the stored procedure is, I've noticed, it does require a little bit more code work and organization. I'd say it's probably been about 10% more code work and documentation than if I were just using SQL Injection.
The chief advantages of the stored procedures approach are
you have massive flexibility for what you want to do
You can store your SQL code into the database and not pollute your R code with potentially huge strings of SQL code
Avoiding SQL injection (again, this is a data security thing, and may not be an issue depending on your employer's policies. I'm strictly forbidden from using SQL injection, so stored procedures are my only option)
It should also be noted that I've not yet explored using Table-Valued parameters in my stored procedures, which might simplify things for me a bit.
In the past, I've gotten around this by running the supremely inefficient sqlQuery with insert into row-by-row to get around this. But I tried this time and no data was written. Although the sqlQuery statement did not have an error or warning message.
Faced it yesterday: in my case the issue was in scheme. The table was actually created but in my user own scheme.
First time you can create it and than you have this error (that object already exists)
After the investigation I found that some packages does not work correctly with schemes.
In the end I used "insert by line" solution. The solution is available here and here

Muli-Option MS Access Reports

I am very new to MS Access and yet have been working (loosely) on a DB for a while. We have a DB that tracks membership. There is a table with all of the member info in there. When new and current customers are added, or pay for the current year, the info is applied to a 'PaidYear' column. For years now, I have been adding a query listing the current years' members and adding a report that displays the output of the query.
I would like to create a report where I could (using a drop-down maybe) select the active year and other options such as City, Company Name, Phone Number, etc. Is there any way to simply set this up? It has to be easy enough for my replacements to intuitively use. ie:
Member Report for [Choose Year] <-- Dropdown
[City] [Company] [Phone] [Select Option]<--- Extra Options for reporting
I have been playing with it for a while and while I can get the design set up, I can't set up the functionality. Thank you so much!!!
Yup, if you want to filter down your report, you can write a little bit of VBA to open your report with a filter (you don't need to use a parameter query for this. It may be more efficient to do this at the query execution level, but as far as i've noticed, the performance is the same to just run the full query and filter it at runtime of the report open (Access might actually just do this behind the scenes, again, I don't really know.
Anyways, lets get to it. Here's a code snippet that you can kind of use as a starting point and adapt.
Create a button that says 'Run Report', let's call it cmdRunReport
In the On Click event for that button, you will put some code. I'm just writing this up now, so I might have some syntax errors (don't have Access on this PC).
dim multiple as boolean
dim filtering as string
filtering = ""
if me.yearDropdown is not null then
filtering = filtering + "[myYearField] = " & me.yearDropdown
multiple = true
end if
if me.cityDroPDown is not null then
if multiple then
filtering = filtering + "AND [myCityField] = '" & me.cityDropdown & "'"
else
filtering = filtering + " [myCityField] = '" & me.cityDropdown & "'"
set multiple = true
end if
end if
if me.CompanyDropDown is not null then
if multiple then
filtering = filtering + "AND [myCompanyField] = '" & me.CompanyDropdown & "'"
else
filtering = filtering + " [myCompanyField] = '" & me.CompanyDropdown & "'"
set multiple = true
end if
end if
DoCmd.OpenReport "yourReport", acViewPreview, , filtering
This is the basis of what you can do. I may have a couple if syntax errors and concatenated the filtering string incorrectly (untested), but that's where you could start.
In english, it just looks at your form's dropdowns that you use to filter. It checks if they are not null, and then concatenates their values into the "filtering" string. This string is used as a parameter in your OpenReport method.
Hope this helps.

INSERT variable values into a table

I have several variables in an SSIS package that I would like inserting into a table.
example:-
#financialMonth, #Status, #Comments
The Variables have been populated along the way with values based on lookups, filename, dates, etc, and I want to store them in a results table.
Is using the execute SQL task the way to do this ?
Do I need to call a sproc and pass those variales as parameters ?
I've tried putting the following T-SQL into the SQLStatement property
INSERT INTO FilesProcessed
(ProcessedOn, ProviderCode, FinancialMonth,
FileName, Status, Comments)
SELECT GETDATE(), 'ABC' , 201006,
'ABC_201005_Testology.csv',
'Imported','Success'
I tried hardcoding the values above to get it to work
These are the columns on the table I'm inserting into
Column_name Type Computed Length
fileID int no 4
ProcessedOn datetime no 8
ProviderCode nchar no 6
FinancialMonth int no 4
FileName nvarchar no 510
Status nvarchar no 40
Comments nvarchar no 510
This is the Expression code that feeds the SQLStatementSource property
"INSERT INTO FilesProcessed (ProcessedOn, ProviderCode, FinancialMonth,
FileName, Status, Comments) SELECT GETDATE() AS ProcessedOn, '"
+ #[User::providerCode] + "' , "
+ (DT_STR,6,1252)#[User::financialMonth] + ", '"
+ #[User::fileName] + "', 'Imported' AS Status,'Successfully' AS Comments "
Unfortunately I'm missing something, and can't quite get it to work.
The Error message I'm getting is ...
Error: 0xC002F210 at Log entry in
FilesProcessed, Execute SQL Task:
Executing the query "INSERT INTO
FilesProcessed (ProcessedOn,
ProviderCode, FinancialMonth,
FileName, Status, Comments) SELECT
GETDATE(), 'ABC' , 201006,
'DAG_201005_Testology.csv',
'Imported','Successfully'" failed with
the following error: "An error
occurred while extracting the result
into a variable of type (DBTYPE_I2)".
Possible failure reasons: Problems
with the query, "ResultSet" property
not set correctly, parameters not set
correctly, or connection not
established correctly.
Please
a). Advise whether the Execute SQL Task is the way to do what I want to do.
b). Give me any pointers or pitfalls to look out for and check.
Thanks in advance.
OK, here is what I did.
I created an Execute SQL task and configured, thus :-
General Tab
ConnectionType = OLE DB
SQLSourceType = Direct Input
SQLStatement = (left blank)
BypassPrepare = True
ResultSet = None
Parameter Mapping
(none - leave blank)
Result Set
(none - leave blank)
Expressions
SQLStatementSource = "INSERT INTO FilesProcessed (ProcessedOn, ProviderCode, FinancialMonth, FileName, Status, Comments) SELECT GETDATE(), '" + #[User::providerCode] + "' , " + (DT_STR,6,1252)#[User::financialMonth] + ", '" + #[User::fileName] + "', 'Import - Success', '" + #[User::fileComments] + "'"
Then as long as I set up the variables and populate them in the variables window (the Expression editor will not let you save an expression that references a variable that does not exist. Keep notepad handy to store the contents while you go back and edit the variables window, and add new variables in ;)
Build the expression slowly, using the Parse expression button regularly to check.
make sure that the data types of the VALUES match the destination column data types.
see: http://social.msdn.microsoft.com/forums/en-US/sqlintegrationservices/thread/e8f82288-b980-40a7-83a6-914e217f247d/
A couple of speculative suggestions
The Error message says An error occurred while extracting the result into a variable of type (DBTYPE_I2). But this is a straight insert statement. There shouldn't be a result except for rows affected. Do you have any parameter mappings erroneously set to Output?
What if you try and run the SQL Query from the error message directly in management studio? Does that give you an error?
In the above table definition FinancialMonth as int datatype as
FinancialMonth int no 4
while inseting casting as :
(DT_STR,6,1252)#[User::financialMonth]
I think it's purely a datatype mismatch with the target table definition.

Resources