In my Access application I join two resultsets with UNION. This worked for years, but now it stopped working, because after the union one text field just shows some crude chinese characters.
This is the setup:
1. select id,fieldA,1 as fieldB from tableA where cond=1
2. select id,"" as fieldA,2 as fieldB from tableA where cond=0
These queries seperately show the correct results. But after I join them with
select * from subquery1 UNION select * from subquery2
the data from fieldA is just some chinese characters like 㼄W. I have no idea where this comes from.
After some trying I found out that the following query shows the correct results:
select * from subquery1 where id=1 UNION select * from subquery2 where id=1
A nice side-effect is the performance improvement, although I have to change the querydef each time. But how come this works and the old version stopped working?
Instead of showing an empty string "", try adding Null
SELECT id, fieldA, 1 as fieldB FROM tableA WHERE cond=1
UNION SELECT id,Null as fieldA,2 as fieldB FROM tableA where cond=0;
For information, I solved a similar issue simply by using UNION ALL, with the side benefit of an improved performance.
The problem is that Access uses the types in the first SELECT statement in a union query to determine the types of the fields in the query. If you use a null value in this first select block, it has no idea what type to use and messes up. The simplest solution is to re-order the select blocks in your query so that the first one does not contain a null entry. Alternatively, the most generic solution is to create a null table with one field of each type you need, but no data in the table :-
Null Values Table
Field Name Data Type
Null Id AutoNumbered
Null Int Number
Null Currency Currency
Null Date Date/time
Null Text Short Text
Then incorporate a dummy SELECT block prior to the first real block that uses the entries from this Null table :-
SELECT
[Null Date] AS [Date],
[Null Id] AS [Index],
[Null Text] AS [Description],
[Null Currency] AS [Income Tax],
[Null Currency] AS [Employers NI],
[Null Currency] AS [Employees NI],
[Null Currency] AS [Amounts Due],
[Null Currency] AS [Payments],
[Null Currency] AS [Balance]
FROM [Null Values Table];
UNION SELECT
[Date],
Int(Null) AS [Index],
"Salary" AS [Description],
[Income Tax],
[Employers NI],
[Employees NI],
[Income Tax] + [Employers NI] + [Employees NI] AS [Amounts Due],
Int(Null) AS [Payments],
[Income Tax] + [Employers NI] + [Employees NI] AS [Balance]
FROM [Salaries Table];
UNION SELECT ...
Related
I am trying to run a query to gather the total items on hand in our database. However it seems i'm getting incorrect data. I am selecting selecting just the amount field and summing it using joins from separate tables based on certain parameters, however if I display additional fields such as order number, and date all of a sudden im getting different data, even though those fields are being used as filters in the query. Is it because its not in the select statement? If it needs to be in the select statement is it possible to not display them?
Here are the two queries.
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt'
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
providing a sum of 21667457.20
and with the added columns
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt', [Requested Delivery Date], sh.No_, tw.[Status]
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
group by sh.[Requested Delivery Date], sh.No_, tw.[Status]
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
order by sh.[Requested Delivery Date] ASC
Providing a sum of 12319998
I'm self taught in SQL so I may be misunderstanding something obvious, thanks for the help.
With no sample data, I am going to have to demonstrate this in principle. In the latter query you have a GROUP BY meaning the scope of the values in the HAVING will differ, and thus the filtering from said HAVING will be different.
Let's take the following sample data:
CREATE TABLE dbo.MyTable (Grp char(1),
Quantity int,
Required int);
INSERT INTO dbo.MyTable (Grp, Quantity, [Required])
VALUES('a',2,7),
('a',14,2),
('b',4, 7),
('b',3,4),
('c',17,5);
Now we'll perform an overly simplified version of your query:
SELECT SUM(Quantity)
FROM dbo.MyTable
HAVING SUM(Quantity) > SUM(Required);
This brings back the value 40; which is the SUM of all the values in Quantity. A value is returned because the total SUM of Required is 25.
Now let's add a GROUP BY like your second query:
SELECT SUM(Quantity)
FROM dbo.MyTable
GROUP BY Grp
HAVING SUM(Quantity) > SUM(Required);
Now we have 2 rows, with the values 16 and 17 giving a total value of 33. That's because the rows where Grp have a value of 'B' are filtered out, as the SUM of Quantity is lower that Required for 'B'.
The same is happening in your data; in the grouped data you have groups where the HAVING condition isn't met, so those rows aren't returned.
I have a question about adding a row number over 2 queries.
My query is:
SELECT
'telxm001001' AS Node,
'1' AS [Speed Dialing],
'0' AS [Spd DI Numbers by Range],
NULL as 'Speed Dialing No.',
REPLACE(TelefonGeschaeft, '+', '00') AS [Call Number],
Nachname AS [Directory Name],
Vorname AS [Directory First Name]
FROM
dbo.MaData
WHERE
(TelefonGeschaeft LIKE '+%')
UNION ALL
SELECT
'telxm001001' AS Node,
'1' AS [Speed Dialing],
'0' AS [Spd DI Numbers by Range],
ROW_NUMBER() OVER (ORDER BY Nachname) AS 'Speed Dialing No.',
REPLACE(MobiltelefonGeschaeft, '+', '00') AS [Call Number],
Nachname AS [Directory Name],
Vorname AS [Directory First Name]
FROM
dbo.MaData
WHERE
(MobiltelefonGeschaeft LIKE '+%')
I have a SQL Server table with 1400 entries. The 2 queries brings me the right results but the row numbers are not correct because the numerations Begins at 1 when the second query starts. So in my query result i have a numeration from 1 to 680 and then the numeration Begins at 1 when the second query starts. Is there a way to add a row numbering after the two queries finished so the numeration is from 1 to 1400?
Best regards
switzly
Apply a ROW_NUMBER ordering over a derived query; supply a discriminator (e.g. queryOrder) through the individual queries to keep the relevant results grouped.
SELECT ROW_NUMBER() OVER (ORDER BY queryOrder, [Directory Name]) AS number
FROM (
SELECT 1 AS queryOrder, [Directory Name] ..
UNION ALL
SELECT 2 AS queryOrder, [Directory Name] ..
) j
Before jump into too techie in to this query, do you want to have the row number for both the queries?
If yes, why are you putting NULL in the first query?
If you want to have row number for both the queries, use it on both the queries.
Otherwise, try put them into another query as below:
select
ROW_NUMBER over ..., Node, [Speed Dialing], ....
from
(<actual query here>) as temp1;
I have to process in an sql as follows. each order is made up of many detail rows. I only need to look at one table, TRA99.
Order number TRAN CODE
123 QEE
123 #23
123 ABC
SELECT
ALL OTRIDC, OTCOM#, OTORD#, OTFL50, OTTRND, OTTRT, OTENT#,
OTSFX#,
OTREL#, OTUSRN, OTTRNC, OTTRN$, OTFL01
FROM ASTDTA.OETRANOT T01
WHERE OTTRNC IN ('QEE', 'QNE')
I want all the Order # which have 'QEE' or 'QNE'. These are QUote codes. We want a report that will tell us, which quotes orders' converted to a real order and which did not.
then if they have as well #23, this tells me that the order was converted or became an actual order. I am not sure how to do this in 1 sql query i was thinking to create a view for all QEE and QNE codes. then run a second query against that looking for #23.
Based on what I think you're trying to do. This will give you all the order numbers which are associated with both QEE or QNE and #23
SELECT T1.OrderNumber
FROM TRA99 T1
WHERE T1.OrderNumber in (
SELECT OrderNumber
FROM TRA99
WHERE TCode IN ('QEE','QNE')
)
AND T1.TCode='#23'
GROUP BY T1.OrderNumber
What you need to do is use a GROUP BY also a EXISTS sub-query can check for the existence of your flag
select t1.[Order Number]
,(CASE WHEN EXISTS(select *
from TRA99 as t2
where t1.[Order Number] = t2.[Order Number]
and t2.[Tran Code] = '#23')
THEN
cast(1 as bit)
ELSE
cast(0 as bit)
END) as HasFlag
from TRA99 as t1
where t1.[Tran Code] in ('QFE', 'QNE')
group by t1.[Order Number]
Working example
NOTE: you did not list what DBMS you are using so I wrote this against Microsoft Sql Server syntax, but you can translate this concept to any DBMS you need.
This question is a continuation from this question
There is a slight change to the database structure however (as I over simplified slightly)
I have a database with data columns as follows:
Key, Instance, User ID, Day, Size, Instance Type
Key - This is the primary key.
Instance - This is a descriptor of the specific instance (this will be unique).
User ID - This will refer to 1 of a number of users where the number will be less than the number of entries in this table.
Day - This is the day the specific user created this instance. It will be one of either Day 1 or Day 2.
Size - This is the size of the data stored.
Instance Type - There are several instance types An instance, itself, will be one of these instance types.
Now in my previous question I was building a nested SQL query to find a distinct users who has instance on day 1 and day 2 and in this case with a specific instance type.
Now I have 2 sets of these queries.
What I would now like to do is a 3rd query and return the database where the User ID does not exist in either of the other queries.
So far I have set up a query but it is REALLY slow (Something to do with the <> comparator in the On statement) and I'm not even 100% sure it does exactly what I want.
This is my SQL statement so far:
Select Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from (((Table
inner join (Select top 90 Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from Table
where Table.[Instance Type]="type1" and
Table.[Day]=1 and
1=1
group by Table.[User ID]) as t2
on Table.[User ID]<>t2.[User ID])
inner join (Select top 90 Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from Table
where Table.[Instance Type]="type1" and
Table.[Day]=2 and
1=1
group by Table.[User ID]) as t3
on Table.[User ID]<>t3.[User ID])
inner join (Select Table.[User ID]
from Table
where 1=1 ) as t4
on Table.[User ID]=t4.[User ID])
where Table.[Instance Type]="type1"
group by Table.[User ID];
Any help or advice on how to get what I'm after would be massively appreciated!
It might make things easier for performance tuning to start with chunking this up as temporary tables (in MS-Access, i guess 'views' or 'make-tables', particularly as your logic seems overly complex (and therefore difficult to maintain and debug!):
Part 1 of your question: "Now in my previous question I was building a nested SQL query to find a distinct users who has instance on day 1 and day 2 and in this case with a specific instance type."
Why don't you first use a 'temp table/make table' or 'view' or whatever (depending on how you're implementing, by first getting a distinct list of userid's with the day.
SELECT DISTINCT Table.UserID, Table.Day
INTO #DistinctListOfUserIDsWithDays /* Not sure of exact syntax in access! */
FROM Table
WHERE Table.Day = 1
OR Table.Day = 2
And then you can get all users that have data for both days, which solves your first part easily, by aggregating the results of the view/query above and using a having clause:
SELECT Table.UserID, COUNT(*)
FROM #DistinctListOfUserIDsWithDays
HAVING COUNT(*) > 1
Now I have 2 sets of these queries.
re: Your new query, "What I would now like to do is a 3rd query and return the database where the User ID does not exist in either of the other queries", here's one simple solution, based on the original query/view above:
SELECT Table.UserID
FROM Table
WHERE UserID NOT IN (SELECT UserID FROM #DistinctListOfUserIDsWithDays)
You cold also outer join #DistinctListOfUserIDsWithDays with the Table and select only those UserID's that return a NULL on the #DistinctListOfUserIDsWithDays side of the query...
getting the following error in access 2010,
the Microsoft access database engine cannot find the input table or query 'Test'.
Make sure it exists and that its name is spelled correctly.
when running,
SELECT
TEST.[CATEGORY CODE] AS CATEGORYCODE
, TEST.[SAMPLE COMPOSITION] AS SAMPLECOMPOSITION
, Sum(TEST.[WPI]) AS [SumOfWPI]
, Sum(TEST.[Mean Freq Year Fav]) AS [SumOfMean Freq Year Fav]
FROM
(
SELECT *
FROM DATA1
WHERE DATA1.[CATEGORY CODE] IN (
SELECT DISTINCT CODES.[CATEGORY CODE]
FROM CODES
)
UNION ALL
SELECT *
FROM DATA2
WHERE DATA2.[CATEGORY CODE] IN (
SELECT DISTINCT CODES.[CATEGORY CODE]
FROM CODES
)
) AS TEST
WHERE TEST.[COUNTRY] = 'UNITED STATES'
AND TEST.[SAMPLE COMPOSITION] IN (
SELECT DISTINCT TEST.[SAMPLE COMPOSITION]
FROM TEST
)
AND TEST.[CATEGORY CODE] IN (
SELECT DISTINCT CODES.[CATEGORY CODE]
FROM CODES
)
GROUP BY TEST.[CATEGORY CODE], TEST.[SAMPLE COMPOSITION]
ORDER BY TEST.[CATEGORY CODE];
I am creating a 4th table TEST using union all by clubbing 2 tables Data1 & Data2 and making sure only the records are for Category codes taken from Codes tables. Any ideas why its giving me this error?
if i remove this line which is a self-join to the table created by union all:
AND TEST.[SAMPLE COMPOSITION] IN (SELECT DISTINCT TEST.[SAMPLE COMPOSITION] FROM TEST)
i am able to run the query....
Also, right now i have specified COUNTRY = "UNITED STATES". But how do i specify COUNTRY="<>UNITED STATES" OR COUNTRY= All Countries, so that i can get Totals for each?
right now i am doing multiple criteria Autofilters to achieve this, but it is taking 1.5 days as the data after clubbing the 2 tables is ~92000 records. So, trying access to achieve the same. If someone can help me, then i can send a sample file containing data.
You can't reference TEST until it is created, and you're creating it as a result of the query. You're going to have to do it with 2 queries, since you need all the results in your UNION ALL.
COUNTRY <> "UNITED STATES" will answer your second question.