Access Query and attributes - sql

The setup is this: every location has many different accounts. Some are supplier only accounts, some are not. Each account has many bills associated with it.
I need to do one of two things:
Create a dynamic attribute in the location table that will tell me if the location is associated with an account (or many) that are supplier only. Should be a true/false attribute.
OR
Create a query that will return all the bills for all the locations that are associated with a supplier only account. I do not want a query that only returns bills from supplier only accounts.
Thanks for you help!

Here's the answer:
Location3PS Query:
SELECT DISTINCT Locations.Number
FROM Locations INNER JOIN Accounts ON Locations.Number = Accounts.[Location Num]
WHERE (((Accounts.[Supplier Only?])=True));
Final Query to Get Bills:
SELECT Bills.*, Location3PS.*
FROM
Location3PS INNER JOIN
(
Locations INNER JOIN
(
Accounts INNER JOIN Bills
ON Accounts.[Account Number] = Bills.[Account Number]
)
ON Locations.Number = Accounts.[Location Num]
)
ON Location3PS.Number = Locations.Number;

You can accomplish this without involving the Locations table, e.g.:
select b.* from
(bills b inner join accounts a on b.[account number] = a.[account number])
inner join
(select distinct c.[location num] from accounts c where c.[supplier only?] = true) l
on a.[location num] = l.[location num]
Alternatively, you can use a correlated subquery, e.g.:
select b.*
from bills b inner join accounts a on b.[account number] = a.[account number]
where exists
(select 1 from accounts c where c.[location num] = a.[location num] and c.[supplier only?] = true)

Related

SQL server inner join not returning Description

Looking for some help trying to get some information out of my point of sale db. It is a MS Sql 13.0.4001.0 database
I have two tables. A "stock" table and a "stock UDF" table. They look a little like this:
The Stock Table lets call "ST" and the Stock UDF table "SU"
Stock Table has the following columns
SKU, Description, UDF1 ID, UDF2 ID,UDF3 ID,UDF4 ID
The Stock UDF table has the following columns
ID, Description
I want to create a query that returns a record but instead of the ID under the UDF1 ID column I want to get the description from the SU table.
A sample record in the ST currently looks like this
SKU, Description, UDF1 ID, UDF2 ID,UDF3 ID,UDF4 ID
1000 Orange 2 1 3 Null
The SU table looks like this
ID, Description
1 Fruit
2 Salads
3 Desserts
4 Vegetables
5 Raw
6 Cooked
I want to create a query that returns the following
SKU Description UDF1 UDF2 UDF3 UDF4
1000 Oranges Salads Fruit Desserts
Not sure how to do the inner join correctly.
Something like this:
select st.SKU, st.Description, st.[UDF1 Id], st.[UDF2 Id], st.[UDF3 Id], st.[UDF4 Id]
from [Stock] as st inner join [Stock UDF] as su on st.UDF1 ID = su.ID
But doesn't return what I want.
Thanks in advance.
You simply need to join to the table with the description multiple times, as follows. Joins are implicitly INNER JOIN, so it's not necessary to state that unless you want to. Note, however, that in this case you must use a LEFT OUTER join type, else where there is no match in the joined table, you will return no rows.
EDIT
I've added COALESCE() functions so that in the event a su.Decription field returns NULL, the query will actually output an empty string instead of the NULL. COALESCE() is a handy function that returns the first non-null value in its set of arguments.
SELECT st.SKU
,st.Description
,COALESCE(su1.Description, '') [UDF1 Desc]
,COALESCE(su2.Description, '') [UDF2 Desc]
,COALESCE(su3.Description, '') [UDF3 Desc]
,COALESCE(su4.Description, '') [UDF4 Desc]
FROM Stock st
LEFT JOIN [Stock UDF] su1 ON st.UDF1 = su1.ID
LEFT JOIN [Stock UDF] su2 ON st.UDF2 = su2.ID
LEFT JOIN [Stock UDF] su3 ON st.UDF3 = su3.ID
LEFT JOIN [Stock UDF] su4 ON st.UDF4 = su4.ID
You need to use left joins as you want stock descriptions even if the record is missing. Specifying join or inner join means that the record/field can't be null and return.
select
st.SKU, st.Description,
st.[UDF1 Id], ISNULL(su1.Description,''),
st.[UDF2 Id], ISNULL(su2.Description,''),
st.[UDF3 Id], ISNULL(su3.Description,''),
st.[UDF4 Id], ISNULL(su4.Description,'')
from [Stock] as st
LEFT join [Stock UDF] as su1 on st.[UDF1 Id] = su1.ID
LEFT join [Stock UDF] as su2 on st.[UDF2 Id] = su2.ID
LEFT join [Stock UDF] as su3 on st.[UDF3 Id] = su3.ID
LEFT join [Stock UDF] as su4 on st.[UDF4 Id] = su4.ID
As there are 4 foreign keys in the [Stock] table (UDF1 ID, UDF2 ID,UDF3 ID,UDF4 ID), you need to join [Stock UDF] table 4 times.
left join [Stock UDF] as su1 on st.UDF1 ID = su1.ID
left join [Stock UDF] as su2 on st.UDF2 ID = su2.ID
left join [Stock UDF] as su3 on st.UDF3 ID = su3.ID
left join [Stock UDF] as su4 on st.UDF4 ID = su4.ID
As there are null values consider using LEFT JOIN instead of INNER JOIN.

MS SQL Merge two queries to get One Result

I am implementing a vehicle management system. I have two different queries, one for fetching all vehicles of an agency and one for fetching drivers. Every vehicle is has a driver assigned to it at a time.
Now I want to merge these two queries to returns vehicles details along with details of the driver assigned to the vehicle.
1st query to get drivers and their names:
SELECT UserInfo.Name
FROM DriverInfo INNER JOIN UserInfo ON DriverInfo.Email = UserInfo.Email
INNER JOIN Agency ON UserInfo.AgencyID = Agency.AgencyID
WHERE (UserInfo.AgencyID = 1)
ORDER BY DriverInfo.DriverId DESC
2nd query to get vehicles details:
SELECT Vehicle.VehicleRegNum AS [Registration Number],
Vehicle.EngineNum AS [Engine Number],
Vehicle.FileRef AS [File Refrence],
Type.Name AS Type,
Make.Name AS Make ,
Vehicle.DriverID AS DriverID
FROM Vehicle INNER JOIN Type ON Vehicle.Type = Type.TypeId
INNER JOIN Make ON Vehicle.Make = Make.MakeId
WHERE (Vehicle.Approve = 1)
AND (Vehicle.AgencyId = 1)
AND (Vehicle.Maintained = 1)
ORDER BY Vehicle.VId DESC
In this query, I am getting the DriverID
and in the DriverInfo:
DriverId, LicenseType, AppointmentDate, LicenseExpiryDate, ContractExpiryDate, Email
Just add on the additional tables in your join.
SELECT Vehicle.VehicleRegNum AS [Registration Number],
Vehicle.EngineNum AS [Engine Number],
Vehicle.FileRef AS [File Refrence],
Type.Name AS Type,
Make.Name AS Make,
DriverInfo.DriverId,
DriverInfo.LicenseType,
DriverInfo.AppointmentDate,
DriverInfo.LicenseExpiryDate,
DriverInfo.ContractExpiryDate,
DriverInfo.Email
FROM Vehicle
INNER JOIN Type
ON Vehicle.Type = Type.TypeId
INNER JOIN Make
ON Vehicle.Make = Make.MakeId
INNER JOIN DriverInfo
ON Vehicle.DriverID = DriverInfo.DriverId
INNER JOIN UserInfo
ON DriverInfo.Email = UserInfo.Email
INNER JOIN Agency
ON UserInfo.AgencyID = Agency.AgencyID
AND Vehicle.AgencyID = Agency.AgencyID
WHERE (Vehicle.Approve = 1)
AND (Vehicle.AgencyId = 1)
AND (Vehicle.Maintained = 1)
ORDER BY Vehicle.VId DESC
I believe the following will work, depending on your requirements you might wanna change the JOIN type of DriverInfo:
SELECT Vehicle.VehicleRegNum AS [Registration Number]
,Vehicle.EngineNum AS [Engine Number]
,Vehicle.FileRef AS [File Refrence]
,Type.NAME AS Type
,Make.NAME AS Make
,UserInfo.NAME AS Driver
FROM Vehicle
INNER JOIN Type ON Vehicle.Type = Type.TypeId
INNER JOIN Make ON Vehicle.Make = Make.MakeId
LEFT JOIN DriverInfo ON DriverInfo.DriverID = Vehicle.DriverID
LEFT JOIN UserInfo ON DriverInfo.Email = UserInfo.Email
AND (UserInfo.AgencyID = 1)
--Agency is never used, so don't join?
--LEFT JOIN Agency ON UserInfo.AgencyID = Agency.AgencyID
WHERE (Vehicle.Approve = 1)
AND (Vehicle.AgencyId = 1)
AND (Vehicle.Maintained = 1)
ORDER BY Vehicle.VId DESC

Append SQL columns based on different JOINs

My problem is I have a table where I want to return a column from an SQL database as two different columns based on different JOIN conditions.
My two select statements:
My first statement returns the check numbers and amounts for all of our checks that have gone through the process of being deposited -> and then ipaced (just a term).
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT,
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
INNER JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
INNER JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID
My second statement returns the check numbers and amounts of the checks that have just been deposited.
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT,
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
I would like to have a table like
IPAC/DEPOSITED AMOUNT DEPOSITED AMOUNT CHECK_NUMBER
--------------------- ---------------- ------------
$4.00 123456
$5.00 654321
I'm using BIRT to compile reports and it really only allows you to chart data based on single data sets (which is a single query) AFAIK. I'd like to chart the total "IPAC/Deposited" amount versus the "Deposited" amount.
You're really close. Wouldn't a UNION query do the trick? Something like this:
SELECT COURTESY_CHECK.CHECK_NUMBER,
COURTESY_CHECK.CHECK_AMOUNT AS [IPAC AMOUNT],
null AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
INNER JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
INNER JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID
UNION
SELECT COURTESY_CHECK.CHECK_NUMBER, null AS [IPAC AMOUNT],
COURTESY_CHECK.CHECK_AMOUNT AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
Edit ... this CASE statement with outer joins might be more efficient -- I think this would work, too:
SELECT COURTESY_CHECK.CHECK_NUMBER,
CASE WHEN IPAC.DEPOSIT_ID IS NOT NULL THEN COURTESY_CHECK.CHECK_AMOUNT
ELSE NULL END AS [IPAC AMOUNT],
CASE WHEN IPAC.DEPOSIT_ID IS NOT NULL THEN NULL ELSE COURTESY_CHECK.CHECK_AMOUNT
END AS [DEPOSITED AMOUNT],
CHECK_DEPOSIT.ID AS DEPOSIT_ID
FROM COURTESY_CHECK
INNER JOIN CHECK_DEPOSIT ON CHECK_DEPOSIT.COURTESY_CHECK_ID = COURTESY_CHECK.ID
LEFT JOIN DEPOSIT ON CHECK_DEPOSIT_ID = DEPOSIT.ID
LEFT JOIN IPAC ON DEPOSIT.ID = IPAC.DEPOSIT_ID

Get DISTINCT record using INNER JOIN

I have the follwong Query on multi tables
SELECT DISTINCT b.BoxBarcode as [Box Barcode], (select case when b.ImagesCount IS NULL
then 0
else b.ImagesCount end) as [Total Images], s.StageName as [Current Stage] ,d.DocuementTypeName as [Document Type],
u.UserName as [Start User],uu.UserName as [Finished User]
FROM [dbo].[Operations] o
inner join dbo.LKUP_Stages s on
o.stageid=s.id
inner join dbo.LKUP_Users u on
u.id=o.startuserid
left join dbo.LKUP_Users uu on
uu.id=o.FinishedUserID
inner join boxes b on
b.id=o.boxid
inner join LKUP_DocumentTypes d on
d.ID = b.DocTypeID
where b.IsExportFinished = 0
when i select count from the Boxes table where IsExportFinished = 0
i got the Count 42 records, when i run the above qoury i got 71 records,
i want just the 42 records in Boxes table to retrived.
You are doing a one-to-many join, i.e. at least one of the tables have multiple rows that match the join criteria.
Step one is to find which table(s) that give the "duplicates".
Once you have done that you may be able to fix the problem by adding additional criteria to the join. I'm taking a guess that the same boxid occurs several times in the Operations table. If that is the case you need to decide which Operation row you want to select and then update the SQL accordingly.
Try this one -
SELECT
Box_Barcode = b.BoxBarcode
, Total_Images = ISNULL(b.ImagesCount, 0)
, Current_Stage = s.StageName
, Document_Type = d.DocuementTypeName
, Start_User = u.UserName
, Finished_User = uu.UserName
FROM (
SELECT DISTINCT
o.stageid
, o.boxid
, o.startuserid
, o.FinishedUserID
FROM dbo.[Operations]
) o
JOIN dbo.LKUP_Stages s ON o.stageid = s.id
JOIN dbo.boxes b ON b.id = o.boxid
JOIN dbo.LKUP_DocumentTypes d ON d.id = b.DocTypeID
JOIN dbo.LKUP_Users u ON u.id = o.startuserid
LEFT JOIN dbo.LKUP_Users uu ON uu.id = o.FinishedUserID
WHERE b.IsExportFinished = 0
I guess that if you change your LEFT JOIN into INNER JOIN you will get 42 records as requested.

Filtering based on COUNT

I have a query that works really well. But I am trying to add a filter so if users_in_this_country is > 1. I know to add users_in_this_country > 1 to the WHERE. But if I add it inside the parenthesis it says invalid column and the same if I add it outside of the parenthesis. This is probably really dumb and easy, but what am I over looking? Thanks!
SELECT u.ContactName
,cu.[User ID]
,c.Name
,c.ID
,cu.[Foreign Table]
,count(*) OVER (PARTITION BY c.ID) AS user_in_this_country
FROM dbo.Country AS c
INNER JOIN dbo.CountryUser AS cu ON c.ID = cu.[Foreign ID]
INNER JOIN dbo.UserColder AS u ON cu.[User ID] = u.ID
WHERE EXISTS (
SELECT *
FROM CountryUser AS cu2
WHERE cu2.[Foreign ID] = cu.[Foreign ID]
AND cu2.[User ID] <> cu.[User ID]
AND cu.[Foreign Table] = 'Country')
The reason you can't refer to it in the WHERE clause is that its very meaning, for a given row, depends on what other rows satisfy the WHERE clause; so it would all be too circular.
The simplest fix is to wrap your entire query in SELECT * FROM ( ... ) t WHERE t.user_in_this_country > 1.
That said, it seems like your query already ensures that user_in_this_country > 1, by virtue of the EXISTS clause, which makes sure that there exists a different CountryUser record that belongs to the same Country and a different User. What am I missing?
With aggregate functions (like COUNT) used in conjuction with OVER clause you have to use a CTE or a subquery, like this
WITH CTE AS (
SELECT u.ContactName
,cu.[User ID]
,c.Name
,c.ID
,cu.[Foreign Table]
,count(*) OVER (PARTITION BY c.ID) AS user_in_this_country
FROM dbo.Country AS c
INNER JOIN dbo.CountryUser AS cu ON c.ID = cu.[Foreign ID]
INNER JOIN dbo.UserColder AS u ON cu.[User ID] = u.ID
WHERE EXISTS (
SELECT *
FROM CountryUser AS cu2
WHERE cu2.[Foreign ID] = cu.[Foreign ID]
AND cu2.[User ID] <> cu.[User ID]
AND cu.[Foreign Table] = 'Country')
)
SELECT *
FROM CTE
WHERE user_in_this_country > 1
Because "users_in_this_country" is not a column, it is an alias which is not valid in the scope of the WHERE clause. I 'm not familiar with "OVER" or PARTITION BY but, my guess is you'd have to do something like this:
WHERE blabla AND (count(*) OVER (PARTITION BY c.ID)) > 1