MySQL Union Query w/ Left Join - Order By Error? - union

We have a Union Query. Here's a basic (similar) example:
SELECT a.Name, b.Info
FROM a
LEFT JOIN b ON (a.ID = b.ID)
WHERE a.Name LIKE "a%"
UNION
SELECT a.Name, b.Info
FROM a
LEFT JOIN b ON (a.ID = b.ID)
WHERE a.Name LIKE "b%"
ORDER BY a.Name, b.Info;
I am receiving an error that says "Unknown column 'b.Info' in 'order clause'".
When I remove the "b.Info" from the end of the ORDER BY clause, it works.
Ideas ?

The Orderby is being applied to the combined result-set - after the Union has taken place. At this point, there is only one table so to speak, so the reference to b.Info will be invalid.
SELECT a.Name AS 'NameCol', b.Info AS 'InfoCol' FROM a LEFT JOIN b ON (a.ID = b.ID) WHERE
a.Name LIKE "a%" UNION SELECT a.Name AS 'Name', b.Info AS 'Info' FROM a LEFT JOIN b ON
(a.ID = b.ID) WHERE a.Name LIKE "b%" ORDER BY NameCol, InfoCol;
Be aware that this could be potentially very slow (with large result sets), as you are forcing MySQL to use a temporary table for the sorting operation.

This problem is described in the MySQL documentation (12.2.8.3 UNION Syntax). You can't use the original table name, so give each column an alias and use this one in the ORDER BY clause:
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one. The following example uses both clauses:
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;
This kind of ORDER BY cannot use column references that include a table name (that is, names in tbl_name.col_name format). Instead, provide a column alias in the first SELECT statement and refer to the alias in the ORDER BY.

Why are you using union at all? this query is the same and faster:
SELECT a.Name, b.Info FROM a LEFT JOIN b ON a.ID = b.ID
WHERE (a.Name LIKE "a%" OR a.Name LIKE "b%") ORDER BY a.Name, b.Info;
Read up on parentheses

I think when you're doing UNION query you should specify column position, not name in the ORDER BY clause. Try ORDER BY 1,2.

Related

Distinct columns after "ORDER BY" in SQL server 2014

I want to distinct columns after ORDER BY points.pPoint.
this is points table diagram:
I want something as following image on the right side but getting result as the left side:
and this is my code:
SELECT TOP(6) MedicalExpertise.meid
FROM physician INNER JOIN
MedicalExpertise ON physician.meid = MedicalExpertise.meid INNER JOIN
points ON physician.phId = points.phID
ORDER BY points.pPoint DESC
Perhaps something like this?
SELECT DISTINCT meid
FROM ( SELECT TOP ( 6 ) MedicalExpertise.meid
FROM physician
INNER JOIN MedicalExpertise ON physician.meid = MedicalExpertise.meid
INNER JOIN points ON physician.phId = points.phID
ORDER BY points.pPoint DESC ) d
ORDER BY 1 DESC;
Simply use distinct keyword,
Ex:
SELECT DISTINCT column1, column2, ...
FROM table_name;
Can you edit the original question what you really want? Does it have to be grouped by any column before getting distinct? Please update the question.

How do I select for each row from a list of elements in an XML column?

I have TableC and TableA. I want all the records from TableC whereas only matching records from TableA so I'm using 'left join'.
The problem is that TableA has an XML column. The XML in that column has following structure
<x:main xmlns:x="x-elements">
<x:rules>
<x:obj>
<ruleName>name1</ruleName>
<createdBy>userA</createdBy>
<type>bbb</type>
</x:obj>
<x:obj>
<ruleName>name2</ruleName>
<createdBy>userA</createdBy>
<type>ccc</type>
</x:obj>
</x:rules>
<x:info>
<x:obj>
<target>ftp:1</target>
<user>userB</user>
</x:obj>
<x:obj>
<target>ftp:3</target>
<user>userA</user>
</x:obj>
</x:info>
</x:main>
I want to get createdBy from XML column for each row where equivalent type is 'ccc'.
Below is my effort
with xmlnamespaces ('x-elements' as x),
res1 as (select x.xmlCol.value('(createdBy)[1]', 'varchar(500)') prop1
from TableC c
left join TableA a
cross apply a.xCol.nodes('x:main/x:rules/x:obj') x(xmlCol)
on c.Id = a.Id
where x.xmlCol.value('(type)[1]', 'varchar(500)') = 'ccc')
select
c.Name,
(select prop1 from res1) prop1
from TableC c
left join TableA a
on c.Id = a.Id
However, I'm getting an error stating
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Can anyone please guide on how to achieve what I'm trying to do here?
P.S Later I would also like to get 'target' from XML column for each row where equivalent user is 'userA'.
(select prop1 from res1) prop1
This is the part of your query that is causing the error. If you want to use this as a subquery, it must return one row for each row of your statement:
select
c.Name,
(select prop1 from res1) prop1
from TableC c
left join TableA a
on c.Id = a.Id
I know nothing about XML querying, but in order to make this query work, you will need to add an ID to the res1 CTE.
res1 as (select x.xmlCol.value('(prop1)[1]', 'varchar(500)') prop1
,c.Id
from TableC c
left join TableA a
cross apply a.xCol.nodes('x:main/x:sub/x:obj') x(xmlCol)
on c.Id = a.Id
where x.xmlCol.value('(prop2)[1]', 'varchar(500)') = 'ccc')
And then change your subquery to be:
(select prop1 from res1 where res1.Id = c.Id) prop1
I realize that my answer only solves the subquery portion of your question, but I hope this helps solve the immediate issue. Someone with more experience querying XML might be able to provide a better overall solution, without the CTE.
If I get this correctly you are creating a CTE, thinking, you need this to get your prop1. And then you do exactly the same joins and filters again...
Wouldn't it be enough to reduce this to:
with xmlnamespaces ('x-elements' as x)
select x.xmlCol.value('(prop1)[1]', 'varchar(500)') prop1
from TableC c
left join TableA a
cross apply a.xCol.nodes('x:main/x:sub/x:obj') x(xmlCol)
on c.Id = a.Id
where x.xmlCol.value('(prop2)[1]', 'varchar(500)') = 'ccc'
As Arthur Daniels has pointed out, the problem is the (select prop1 from res1) prop1 which will return more than one element and therefore cannot be called as column within a sub-select...
EDIT: How do shred your XML
Removed....
EDIT 2: I must admit you should really train on how do I explain what I need ...
Might be that you are looking for this:
This will joing TableC and TableA as you did it yourself and then pick the value of "createdBy" where the "type" = "ccc".
The next XQuery first picks the username we found in the first go at "ccc" and finds the fitting "target".
WITH XMLNAMESPACES('x-elements' AS x)
SELECT c.*
,a.*
,a.xCol.value('(//x:rules/x:obj[type="ccc"]/createdBy)[1]','varchar(500)') AS CreatedBy
,a.xCol.value('let $user:=(//x:rules/x:obj[type="ccc"]/createdBy)[1] return (//x:info/x:obj[user=$user]/target)[1]','varchar(500)') AS Target
FROM TableC AS c
LEFT JOIN TableA AS a on c.Id = a.Id

Column 'Products.CDF_Code_Tx' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.?

I am not understanding this Error message.
Column 'Products.CDF_Code_Tx' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Any guidance on how I could get around this , I think I need a GROUP BY clause in but when I place one it makes a lot of things ambiguous.
Here is my code.
Select Cdf_Code_Tx, ProjectNo,(CDF_New_des1_Tx+CDF_New_des2_Tx) As Description,Max(Convert(Date, [Last Call Back],103)) As LastCallBack
From Products
Inner Join SpecDetails On CDF_Code_Tx = ProductRef
Inner Join Projects2 On ProjectNo = PID
Order By (Convert (Date, [Last Call Back], 103))
Thank you in advance!
Aggregate functions in the SELECT clause list provide information about each group instead of individual rows... Read more GROUP BY (Transact-SQL)
eg.
By doing something like below will lead to error "invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause"
Select T1.Col1,T1.Col2,MAX(T2.Col1)
From Table1 T1
Inner Join Tabel2 T2 ON T2.Id = T1.ID
What you shoud do is
Select T1.Col1,T1.Col2,MAX(T2.Col1)
From Table1 T1
Inner Join Tabel2 T2 ON T2.Id = T1.ID
Group By T1.Col1,T1.Col2

SQL: How do I check for records in one table that aren't in another?

I want to find records that are in one table but not in another. Except the records aren't formed the same. So I'm wanting to determine the columns I want to use to compare against. I thought I had it worked out with the following code, but it doesn't seem to be working (Returns zero records)...
SELECT A.Name, A.Position, A.[Year]
FROM TABLE A
WHERE NOT EXISTS (
SELECT B.Name, B.Position, B.[Year]
FROM TABLE B
)
Or should I be doing this with some kind of join? Thanks...
You're missing the WHERE clause to compare the two tables to one another:
SELECT A.Name, A.Position, A.[Year]
FROM TABLE A
WHERE NOT EXISTS (
SELECT B.Name, B.Position, B.[Year]
FROM TABLE B
WHERE B.Name = A.Name AND B.Position = A.Position AND B.[Year] = A.[Year]
)
Assuming you want use all three columns to do the comparison you can use an anti-join.
SELECT A.Name, A.Position, A.[Year]
FROM TABLE_A A
LEFT JOIN TABLE_B B
ON a.name = b.name
and a.position = b.position
and a.[Year] = b.[Year]
WHERE
b.name is null
You can use an left outer join on table b with a where clause looking for null values.
I am assuming that everything in the first query comes from table A and everything in the second comes from table B
Select A.Name, A.Position, A.[Year]
from A
Left Join B on A.Name = B.Name and A.Position = B.Position and A.[Year] = B.[Year]
where B.Name is Null

How to Merge SQL Query

i want the Output of the Following Query in One row
i want to merge Below SQL Query
Help me please
select Provider_ID,Circel_ID,count(distinct td_all.ID),t_det.BillNoTemp from TAPINOUT_DIFFERENCES_ALL td_all
inner join TransferDetails t_det on td_all.bill_no=t_det.Bill_No
where td_all.bill_no not in (select bill_no from TAPINOUT_DIFFERENCES_ALL where Status='Open') and sourcename='TransferDetails'
group by td_all.Provider_ID,td_all.Circel_ID,t_det.BillNoTemp
order by td_all.Provider_ID,td_all.Circel_ID
select td_all.Provider_ID,td_all.Circel_ID,TAP_DET.BillNoTemp ,count(distinct td_all.ID)as count from TAPINOUT_DIFFERENCES_ALL td_all
INNER JOIN TAPIN_Details TAP_DET ON td_all.FILENAME=TAP_DET.FLNAME
where td_all.SOURCENAME='TransferDetails' and td_all.Status='Open'
group by td_all.Provider_ID,td_all.Circel_ID,TAP_DET.BillNoTemp
order by td_all.Provider_ID,td_all.Circel_ID
select td_all.Provider_ID,td_all.Circel_ID,TAP_DET.BillNoTemp,count(distinct td_all.ID)AS COUNT from TAPINOUT_DIFFERENCES_ALL td_all
inner join TAPIN_Details TAP_DET on td_all.FILENAME=TAP_DET.FLNAME
where td_all.anb_comments='Invoice Not Found'
group by td_all.Provider_ID,td_all.Circel_ID,TAP_DET.BillNoTemp order by td_all.Provider_ID,td_all.Circel_ID
select td_all.Provider_ID,td_all.Circel_ID,t_det.BillNoTemp,count(distinct td_all.ID) from TAPINOUT_DIFFERENCES_ALL td_all
inner join TransferDetails t_det on td_all.bill_no=t_det.Bill_No
where td_all.anb_comments='IT File not found'
group by td_all.Provider_ID,td_all.Circel_ID,t_det.BillNoTemp order by td_all.Provider_ID,td_all.Circel_ID
I think you're looking for the UNION operator, which lets you append the results of multiple queries into a single result set.
It works like so:
SELECT columns FROM tbl1 WHERE criteria
UNION
SELECT columns FROM tbl2 WHERE criteria
Use UNION keyword between statements.
SELECT bla, bla2 FROM table1
UNION ALL
SELECT bla3, bla4 FROM table2

Resources