Joining 4 Tables with different conditions - sql

I use vb.net 2012 and msaccess2016 as database. I Have 4 tables. Item master,closing,Purchase,Issue. Now I want to get the result for a period in below formatted datagridview. Below are columns.
Item Name(Item Master)
Category(Item Master)
Unit(Item Master)
Sum of Quantity(closing)
Sum of Quantity(Purchase)
Sum of Quantity(Issue)
I have create a query with Item master and Closing and it's working. But when I try to purchase or issue there is no data. Purchase and issue table got no data.
Dim sdate, edate As Date
sdate = dtsdate.Value
edate = dtedate.Value
Dim sqlSelect As String = "SELECT itemmaster.[Item Name], itemmaster.Category, itemmaster.Unit," _
& " Sum(Closing.Qty) AS Opening FROM itemmaster INNER JOIN Closing ON " _
& "itemmaster.[Item Name] = Closing.[Item Name] WHERE(((Closing.closeDate) >= #" & sdate & " # And (Closing.closeDate) <=#" & edate & " #))" _
& " GROUP BY itemmaster.[Item Name], itemmaster.Category, itemmaster.Unit"
Try
Dim con As New Odbc.OdbcConnection
con.ConnectionString = "Dsn=sdbinventory;"
Dim dt As New DataTable("user2")
Using cmd = New Odbc.OdbcCommand(sqlSelect, con)
con.Open()
Dim da As New System.Data.Odbc.OdbcDataAdapter(sqlSelect, con)
da.Fill(dt)
con.Close()
End Using
dgtvreport.DataSource = dt
Catch ex As Exception
Throw
End Try
Can you please help me to add rest two columns.
Thanks
My query
PARAMETERS sdate DateTime, edate DateTime;
SELECT itemmaster.[Item Name], itemmaster.Category, itemmaster.Unit, Sum(Closing.Qty) AS SumOfQty1, Sum(Purchase.Qty) AS SumOfQty, Sum(Issue.Quantity) AS SumOfQuantity
FROM ((itemmaster INNER JOIN Closing ON itemmaster.[Item Name] = Closing.[Item Name]) INNER JOIN Issue ON itemmaster.[Item Name] = Issue.[Item Name]) INNER JOIN Purchase ON itemmaster.[Item Name] = Purchase.[Item Name]
WHERE (((Closing.closeDate)>=[sdate] And (Closing.closeDate)<=[edate]) AND ((Purchase.PDate)>=[sdate] And (Purchase.PDate)<=[edate]) AND ((Issue.Idate)>=[sdate] And (Issue.Idate)<=[edate]))
GROUP BY itemmaster.[Item Name], itemmaster.Category, itemmaster.Unit;
I have tried to run it in access. Also have added sample data. I just want to import all item names,category and unit from itemmaster. Now I want to add opening stock in next column and purchase and issue. I want to create and itemwise report.
Like
Item Name Category Unit Opening Purchased Issued Balance
item1 Grocery Kg 2 3 4 1
item2 beverages PCS 0 1 1 0
Item3 vegetables kg 2 0 0 2
item4 consumable Pkt 10 2 1 11

#june7 yes I belive your is the best answer which is also know by me but I have searched if there is any other option and in this process you have really gave me the in depth knowledge and differences about the different type of queries. thanks.

Related

How to put a criteria for the function in a query?

I have a query where one of the fields is a function I wrote to get the due dates for trainings.
The function works and when I run my query it gives the correct dates but when I try to put in a criteria in the query to for example only output the due dates that are <31 days it gives me the error:
Data type mismatch in criteria expression
This is in the field for the query:
Due Date: getDueDate([Workday_Excel_Update].[Course Number])
This is the function:
Function getDueDate(CourseNum As String)
Dim yearCounter As Integer
Dim yearStart As Date
Dim yearNow As Integer
Dim monthFreq As Integer
Dim daysDue As Integer
'check if course number is part of the tracked trainings
If Not IsNull(DLookup("CourseName", "CourseNumbers", "CourseNumber = '" & CourseNum & "'")) Then
'if it is part of tracked training calculate date
monthFreq = DLookup("[Months]", "CourseNumbers", "CourseNumber = '" & CourseNum & "'")
yearStart = DLookup("[Frequency]", "CourseNumbers", "CourseNumber = '" & CourseNum & "'")
yearCounter = Year(yearStart)
yearNow = Year(Date)
While yearCounter < yearNow
yearStart = DateAdd("m", monthFreq, yearStart)
yearCounter = yearCounter + (monthFreq / 12)
Wend
daysDue = CInt(DateDiff("d", Date, yearStart))
'Else
'daysDue = 0
End If
getDueDate = daysDue
End Function
Example data:
CourseNumbers (Table)
CourseNumber
CourseName
Frequency
Months
1234
1234-training
1900-12-31
12
Workday_Excel_Update (Linked Table)
User ID
Badge ID
First Name
Last Name
Email Address
Primary Supervisor
Completion Date
Course Title
Course Number
Lesson Completion Status
0022334455
54321
Frank
Smith
frank.smith#work.com
John Leblanc
2021-05-20 2:59:54 PM
11234-training
1234
Not Started
SQL code of the Query:
SELECT Workday_Excel_Update.[User ID], Workday_Excel_Update.[Badge ID], Workday_Excel_Update.[First Name], Workday_Excel_Update.[Last Name], Workday_Excel_Update.[Email Address], Workday_Excel_Update.[Primary Supervisor], Workday_Excel_Update.[Completion Date], (getDueDate([Workday_Excel_Update].[Course Number])) AS [Days Until Due Date], Workday_Excel_Update.[Course Title], Workday_Excel_Update.[Lesson Completion Status]
FROM CourseNumbers INNER JOIN Workday_Excel_Update ON CourseNumbers.CourseNumber = Workday_Excel_Update.[Course Number]
WHERE (((Workday_Excel_Update.[Lesson Completion Status])<>"Completed" Or (Workday_Excel_Update.[Lesson Completion Status]) Is Null))
ORDER BY (getDueDate([Workday_Excel_Update].[Course Number]));
The getDueDate() function in the query will take as input a course number from another table which has a registration date for each employee. The registration date goes through a DateDiff() with the calculated due date and outputs an integer indicating the number of days left until the training is due or the number of days past the due date.
Query criteria
I also get the following error when I try to filter the query

Querying multiple tables and displaying the outcome wtih SQL and Access

I need to display the customers that have purchased a product (based on a user search) in a list box. I have five different tables in Access which store different information and that relate to each other with IDs (using combox boxes in vb). I need to be able to search for a product, for example "White Bread", the program then should display the customer's full name and address as stored in the database.
Table: TransactionDetails
Fields: ID, stockID, custTransID
Table: CustomerTransaction
Fields: ID, custID, dateOfTransaction
Table: CustomerAccountDetails
Fields: ID, custFullName, custAddress, custLandline,
custMobile, custDOB, custCreditDetails
Table: StockDescription
Fields: ID, stockName, stockDesc, stockPrice
Table: SupplierDetails
Fields: ID, supplierName, supplier Address
I think I need to use INNER JOIN to query multiple tables at once but I am unsure of the syntax (I'm new to SQL). So far I have this:
Dim productSearch As String
productSearch = productSrchInput.Text
Dim databaseConnection As New OleDb.OleDbConnection
Dim counter As Integer
Dim array(10) As String
databaseConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=assignment5database.accdb"
databaseConnection.Open()
Dim searchDatabase As OleDbCommand = New OleDbCommand("SELECT CustomerAccountDetails.custFullName, CustomerAccountDetails.custAddress " & _
"FROM CustomerAccountDetails " & _
"INNER JOIN StockDescription ON TransactionDetails.stockID = TransactionDetails.custTransID " & _
"WHERE StockDescription.stockName = '" & productSearch & "'", databaseConnection)
Dim searchResults As OleDbDataReader = searchDatabase.ExecuteReader
counter = 1
Do While searchResults.Read
srchResultsList.Items.Add(searchResults.Item(0))
counter += 1
Loop
databaseConnection.Close()
You are missing some of the joins that connect the customer to the stock details. Here is the SQL that Access will expect in order to pull the data based on your description. The parentheses may seem extraneous, if you are used to SQL server or MySQL, but Access will throw a fit if you leave them out.
SELECT CustomerAccountDetails.custFullName, CustomerAccountDetails.custAddress, StockDescription.stockName
FROM StockDescription
INNER JOIN ((CustomerAccountDetails
INNER JOIN CustomerTransaction ON CustomerAccountDetails.ID = CustomerTransaction.custID)
INNER JOIN TransactionDetails ON CustomerTransaction.ID = TransactionDetails.custTransID) ON StockDescription.ID = TransactionDetails.StockID
WHERE StockDescription.stockName="something"
As noted by Fionnuala, I will almost always build a query that has multiple joins in it using the Access query designer before putting it in code. I almost always leave out a set of parentheses or try to write the query in a structure that SQL Server would expect and get rejected by Access.
I think you could be able to use an inner join but perhaps a "union" may be more efficient.
http://www.w3schools.com/sql/sql_union.asp is good for improving sql knowledge, it helped me a lot.

Excel VBA - INNER JOIN Issue

I've got an issue with an Inner Join statement I am using to access data from my Access Database. What I am expecting to happen is that I run through the record set for each product. When a product was ordered more then once, I dont add it to the excel sheet, instead I increment the number ordered and the total cost.
The problem I am having is that instead of it working the way I described above, it is adding a product to the excel sheet for every time it was ordered. I have discovered that it is printing the products in the order that they were ordered (By their OrderID) which is not included in my code.
Any help?
Here is the code :
Public Sub WorksheetLoop()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim stDB As String, stSQL As String, stSQLTwo As String, stProvider As String
Dim sheetName As String, stProdName As String
Dim suppNum As Integer, prodNum As Integer
Dim WS_Count As Integer
Dim I As Integer
suppNum = 1
prodNum = 1
stDB = "Data Source= " & ThisWorkbook.Path & "\obsDatabase.accdb"
stProvider = "Microsoft.ACE.OLEDB.12.0"
'Opening connection to database
With cn
.ConnectionString = stDB
.Provider = stProvider
.Open
End With
' Set WS_Count equal to the number of worksheets in the active
' workbook.
WS_Count = ActiveWorkbook.Worksheets.Count
' Begin the loop.
For I = 2 To WS_Count
ActiveWorkbook.Worksheets(I).Range("A1") = "Company Name - " + ActiveWorkbook.Worksheets(I).Name + ""
ActiveWorkbook.Worksheets(I).Range("A2") = "Item Number"
ActiveWorkbook.Worksheets(I).Range("B2") = "Description"
ActiveWorkbook.Worksheets(I).Range("C2") = "Unit"
ActiveWorkbook.Worksheets(I).Range("D2") = "Cost Per Unit"
ActiveWorkbook.Worksheets(I).Range("E2") = "Quantity"
ActiveWorkbook.Worksheets(I).Range("F2") = "Total Cost"
ActiveWorkbook.Worksheets(I).Range("G2") = "Amount Remaining"
'Function to retrieve info!
stSQL = "SELECT Products.ProductID, Products.ProductName, Products.ProductDescription, Products.ProductUnit, LineItems.UnitPrice, LineItems.Quantity, LineItems.TotalPrice " & _
"FROM Products INNER JOIN LineItems ON LineItems.ProductID = Products.ProductID WHERE Products.SupplierID = " & suppNum & " "
rs.Open stSQL, cn
With rs
Do Until .EOF
If ActiveWorkbook.Worksheets(I).Range("A65536").End(xlUp) = rs.Fields("ProductName") Then
If ActiveWorkbook.Worksheets(I).Range("D65536").End(xlUp) = rs.Fields("UnitPrice") Then
ActiveWorkbook.Worksheets(I).Range("E65536").End(xlUp) = ActiveWorkbook.Worksheets(I).Range("E65536").End(xlUp) + rs.Fields("Quantity")
ActiveWorkbook.Worksheets(I).Range("F65536").End(xlUp) = ActiveWorkbook.Worksheets(I).Range("F65536").End(xlUp) + rs.Fields("TotalPrice")
End If
Else
ActiveWorkbook.Worksheets(I).Range("A65536").End(xlUp).Offset(1, 0) = rs.Fields("ProductName")
ActiveWorkbook.Worksheets(I).Range("B65536").End(xlUp).Offset(1, 0) = rs.Fields("ProductDescription")
ActiveWorkbook.Worksheets(I).Range("C65536").End(xlUp).Offset(1, 0) = rs.Fields("ProductUnit")
ActiveWorkbook.Worksheets(I).Range("D65536").End(xlUp).Offset(1, 0) = rs.Fields("UnitPrice")
ActiveWorkbook.Worksheets(I).Range("E65536").End(xlUp).Offset(1, 0) = rs.Fields("Quantity")
ActiveWorkbook.Worksheets(I).Range("F65536").End(xlUp).Offset(1, 0) = rs.Fields("TotalPrice")
End If
rs.MoveNext
Loop
End With
rs.Close
suppNum = suppNum + 1
ActiveWorkbook.Worksheets(I).Columns("A:A").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("B:B").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("C:C").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("D:D").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("E:E").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("F:F").EntireColumn.AutoFit
ActiveWorkbook.Worksheets(I).Columns("G:G").EntireColumn.AutoFit
Next I
cn.Close
End Sub
I'm not sure if I am missing the point. But could you clarify your end goal? Does it have to be done via Excel VBA?
If what you are trying to achieve is a tab with each suppliers orders on, with one row per product and a total quatity for that product, then I would consider creating a query in the database itself and pass the supplier id parameter and any other parameters to the query. The query could then handle the grouping and counting of products and quatitys as this would be an aggregrate query.
This way you can have a refreshable query on each tab and wrtie VBA to refresh them individually or all together whichever suits your needs.
I would always try to avoid complex VBA coding as it's buggy at the best of times and becomes difficult to maintain once distributed.
Another option would be pull all the product data into another tab which you could Hide via VBA and use formula like SUMPRODUCT to display the information on the various tabs. Or use a combo style box to select your supplier and dynamically change the result set.
As I said in the beginning I may be missing the point, but if not and you would like help with my option(s) let me know, and if I am please clarify your question.
For your INNER JOIN issue, you would need to use an agregate query not a stright forward select. This is because your database (I assume) can have one supplier which can order the same product more than once (A one to Many relationship), from what you have supplied you have a quantity column in the LineItems table so I assume the duplicate product ID is from two or more seperate orders from the same supplier. Here is an example of the query, also consider aliasing your tables names, it makes following the code easier.
SELECT
p.ProductID
,p.ProductName
,p.ProductDescription
,p.ProductUnit
,SUM(l.UnitPrice)
,SUM(l.Quantity)
,SUM(l.TotalPrice)
FROM Products p
INNER JOIN LineItems l
ON l.ProductID = p.ProductID
WHERE p.SupplierID = 1
GROUP BY
p.ProductID
,p.ProductName
,p.ProductDescription
,p.ProductUnit
Regards
Kevin
You're only ever comparing the current product name to the last line added to the worksheet but nothing in your SQL query enforces any ordering to the results.
This would be OK if the data was returned like this:
ProductName, Quantity
foo, 7
foo, 4
bar, 3
but would not be OK if the data was returned like this:
ProductName, Quantity
foo, 7
bar, 3
foo, 4
You could use an ORDER BY clause and work with your current macro but, as other people have pointed out, you could use SQL to combine the data and this should be a simpler solution

Concatenate multiple rows in one field in Access? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Ms Access Query: Concatenating Rows through a query
I have a table that has many columns, but two of interest: Order Number and Product Type. Currently the table has multiple Product Types per Order. If the customer ordered phone service, TV service and Internet service, then there would be three records - one for each service but all having the same order number. I want to create a reference table to store a concatenated string with all of the services the customer ordered. This way I can summarize my data using this more logical method. I'm using a standard Access 2010 database.
**Current table:**
Order Number | Product Types
100001 | TV
100001 | Phone
100001 | Internet
100002 | Phone
100003 | TV
100003 | Internet
Desired reference table
100001 | TV/Phone/Internet
100002 | Phone
100003 | TV/Internet
Allen Browne provides a function which you may find useful for this: Concatenate values from related records. Save that function's code in a standard module.
SELECT DISTINCT
[Order Number],
ConcatRelated("[Product Types]",
"YourTable",
"[Order Number] = " & [Order Number],
"[Product Types]",
"/"
) AS All_Product_Types
FROM YourTable;
I tested that query in Access 2007 with your sample data saved in a table named "YourTable". It returned the results you asked for. However, this only works from within an Access session. If you wanted to run this query from outside Access (like from ASP), user-defined functions are not available, so you would get an error about ConcatRelated() not recognized.
So you can use a query to retrieve the concatenated values whenever you need them. However if you store those concatenated values, they can quickly be out of sync with changes to the base table's data.
If I understand the question, you're asking how to get the order numbers of just those orders who have TV, AND phone, AND internet. If you're just interested in those order numbers you could run a query like:
SELECT Distinct Table1.OrderNumber
FROM (Select OrderNumber from Table1 where [product types]= "Internet") AS i
INNER JOIN ((Select OrderNumber from Table1 where [product types]="Phone") AS p
INNER JOIN ((Select OrderNumber from Table1 Where [product types]= "TV") AS tv
INNER JOIN Table1 ON tv.OrderNumber = Table1.OrderNumber) ON p.OrderNumber = Table1.OrderNumber) ON i.OrderNumber = Table1.OrderNumber;
As was pointed out by onedaywhen in an early post on SO, this is easier with ADO:
Sample query:
SELECT [Order Number],
ConcatADO("SELECT [Product Types] FROM Orders
WHERE [Order Number]=" & [Order Number],", "," : ") AS Cat
FROM Orders
GROUP BY [Order Number], 2;
Function using ADO
Function ConcatADO(strSQL As String, strColDelim, _
strRowDelim, ParamArray NameList() As Variant)
Dim rs As New ADODB.Recordset
Dim strList As String
On Error GoTo Proc_Err
If strSQL <> "" Then
rs.Open strSQL, CurrentProject.Connection
strList = rs.GetString(, , strColDelim, strRowDelim)
strList = Mid(strList, 1, Len(strList) - Len(strRowDelim))
Else
strList = Join(NameList, strColDelim)
End If
ConcatADO = strList
Exit Function
Proc_Err:
ConcatADO = "***" & UCase(Err.Description)
End Function
You should not create a reference table that concatenates records. That is denormalizing the database.
You can try a crosstab query like below, but I have not tested it. You can read here for more information.
TRANSFORM First([Product Types]) AS Product
SELECT [Order Number], First([Product Types])
FROM CurrentTable
GROUP [Order Number]

crystal report and sql commands

I have a problem in showing data content from joined table in crystal report my sql query is good and it shown my own data but i when fill crystal report datasource and show it the crystal repeat duplicate and more data my code is:
Dim rep As CrystalReport1 = New CrystalReport1()
Dim objcon = New SqlConnection("data source=(local);initial catalog=hesabres;user id='sa';password='Maysam7026'")
Dim objcom = New SqlCommand
Dim objdata As New DataTable
Dim objdr As SqlDataReader
objcom.CommandText = " SELECT customer.customer_name, customer.customer_tel, orders.order_stuff_name, orders.order_number" & _ " FROM hesabres.dbo.orders orders inner JOIN hesabres.dbo.customer customer ON orders.order_customer_id=customer.customer_id"
objcom.Connection = objcon
objcon.Open()
objdr = objcom.ExecuteReader
objdata.Load(objdr)
rep.SetDataSource(objdata)
CrystalReportViewer1.ReportSource = rep
in fact may bought one chair and ball and jahan bought one ball!
Crystal reports does not show any data itself.
If your database query result is fine then their is something with their code.
I will suggest that please review your code in detail.
Apply distinct keyword in select statement as below and then check it
SELECT Distinct customer.customer_name, customer.customer_tel,
orders.order_stuff_name, orders.order_number" & _ "
FROM hesabres.dbo.orders orders
inner JOIN hesabres.dbo.customer customer
ON orders.order_customer_id=customer.customer_id