This query gives all the templateId that are assigned to product id less than 5 and that's the expected output. But we wanted to achieve that without using the sub query in the where clause (Highlighted in red).
If I just remove the subquery then the output will be all the templateId from templateproduct table. we don't wnat that. what we want is the template id that's only assigned from product 1 to 5. so our expected output is:
100
102
today we are acheiving this using additional subquery, we wanted to acheive the same result without using the subquery.
we are using sql 2008
You can do this using a LEFT JOIN in place of a subquery, and check for NULL.
SELECT DISTINCT tp.template_id
FROM templateproduct tp
LEFT JOIN templateproduct tp2
ON tp.template_id = tp2.template_id AND tp2.prod_id IN (6, 7, 8, 9, 10)
WHERE tp.prod_id < 5
AND tp2.template_id IS NULL
You can do a similar thing using GROUP BY and check that there are 0 matching templates linking to the excluded product ids:
SELECT tp.template_id
FROM templateproduct tp
LEFT JOIN templateproduct tp2
ON tp.template_id = tp2.template_id AND tp2.prod_id IN (6, 7, 8, 9, 10)
WHERE tp.prod_id < 5
GROUP BY tp.template_id
HAVING COUNT(tp2.template_id) = 0
Depending on your data and indexing, this may or may not be more efficient than a subquery - I suggest you try it out. In any event, there is no reason to have any INNER JOINs at all to get the results you are seeking:
SELECT DISTINCT tp.template_id
FROM templateproduct tp
WHERE tp.prod_id < 5
AND tp.template_id NOT IN (
SELECT tp2.template_id FROM templateproduct tp2 WHERE tp2.prod_id IN (6, 7, 8, 9, 10)
)
Try these out and see which performs better for you. And of course, check the query plan to see why this is.
It's because your where clause should be tp.prod_id <= 5
Not 100% sure about the layout of your columns but something like this perhaps:
SELECT
TemplateID,
--Other fields here
FROM
Product pr INNER JOIN TemplateProduct tp on pr.prod_id = tp.prod_id
INNER JOIN Template tr on tp.templateID = tr.templateID AND tr.prod_id = pr.prod_id
WHERE
tp.prod_id < 5
Related
I dont't get it. I changed some of the code. In the WPLEVENT Table are a lot of Events per person. In the Persab-Table are the Persons with their History. Now I need the from the Persab Table just that row wich matches the persab.gltab Date nearest to the WPLEVENT.vdat Date. So all rows from the WPLEVENT, but just the one matching row from the PERSAB-Table.
SELECT
persab.name,
persab.vorname,
vdat,
eventstart,
persab.rc1,
persab.rc2
FROM wplevent
INNER JOIN
persab ON WPLEVENT.PersID = persab.PRIMKEY
INNER JOIN
(SELECT TOP 1 persab.rc1
FROM PERSAB
WHERE persab.gltab <= getdate() --/ Should be wplevent.vdat instead of getdate()
) NewTable ON wplevent.persid = persab.primkey
WHERE
persid ='100458'
ORDER BY vdat DESC
Need to use the MAX() function with the proper syntax by supplying an expression like MAX(persab.rc1). Also need to use GROUP BY for the second column rc2 in the subquery (although it looks like you do not need it). Finally you are missing the ON clause for the final INNER JOIN. I can update the answer to fix the query if you provide that information.
SELECT
Z1PERS.NAME
, Z1PERS.VORNAME
, WPLEVENT.VDat
, WPLEVENT.EventStart
, WPLEVENT.EventStop
, WPLEVENT.PEPGROUP
, Z1SGRP.TXXT
, PERSAB.GLTAB
, Z1PERS.PRIMKEY AS Expr1
, PERSAB.PRIMKEY
FROM
Z1PERS
INNER JOIN
WPLEVENT ON Z1PERS.PRIMKEY = WPLEVENT.PersID
INNER JOIN
Z1SGRP ON WPLEVENT.PEPGROUP = Z1SGRP.GRUPPE
INNER JOIN
(
SELECT MAX(Persab.rc1) --Fixed MAX expression
, persab.rc2
FROM
persab
GROUP BY
persab.rc2 --Need to group on rc2 if you want that column in the query otherwise remove this AND the rc2 column from select list
WHERE
WPLEVENT.PersID = PERSAB.PRIMKEY
AND WPLEVENT.VDat <= PERSAB.GLTAB
) --Missing ON clause for the INNER JOIN here
WHERE z1pers.vorname = 'henning'
I have two SQL tables, news and newsSections. I want to to display the top rows from a group by when selecting 4 different types of the news sections. For example:
SELECT TOP (4) a.newsID, a.title, a.clicked, a.path, a.newsDate, c.sectionName, a.sectionID
FROM dbo.News a INNER JOIN
dbo.newsSection c
ON a.sectionID = c.SectionID
WHERE (c.SectionID = 21) OR (c.SectionID = 23) OR (c.SectionID = 36) OR (c.SectionID = 37)
GROUP BY c.sectionName, a.newsID, a.title, a.clicked, a.path, a.newsDate, a.sectionID
ORDER BY a.newsDate DESC
You can use APPLY:
SELECT n.*, ns.sectionName
FROM dbo.newsSection ns CROSS APPLY
(SELECT TOP 1 n.*
FROM dbo.News n
WHERE n.sectionID = ns.sectionID
ORDER BY n.newsDate DESC
) n
WHERE ns.SectionID IN (21, 23, 36, 37);
From your query, you're going to the the 4 most recent articles from ALL of the the news sections pooled together -- meaning, you may get multiple articles from a single section and no articles from another section if there has been more recent activity in some sections vs. others.
I'm guessing what you actually want is the most recent article from EACH of the sections. If so, then the reply by Gordon Linoff would do the trick -- except that he left in the 'ON' clause in the query. (Gordon himself pointed this out.) Should look more like this:
SELECT n.*, ns.sectionName
FROM dbo.newsSection ns CROSS APPLY
(SELECT TOP 1 n.*
FROM dbo.News n
WHERE n.sectionID = ns.sectionID
ORDER BY n.newsDate DESC
) n
WHERE ns.SectionID IN (21, 23, 36, 37);
First off I am using SQL Server.
I am joining a table on itself like in the example below:
SELECT t.theDate,
s.theDate,
t.bitField,
s.bitField,
t.NAME,
s.NAME
FROM table1 t
INNER JOIN table1 s ON t.NAME = s.NAME
If I take a random row (i.e. X) from the dataset produced.
Can I compare values in any field on row X to values in any field on row X-1 OR row X+1?
Example: I want to compare t.theDate on row 5 to s.theDate on row 4 or s.theDate on row 3.
Sample data looks like:
Desired results:
I want to pull all pairs of rows where the t.bitfield and s.bitfield are opposite and t.theDate and s.theDate are opposite.
From the image the would be row (3 & 4), (5 & 6), (7 & 8) ... etc.
I really appreciate any help!
Can it be done?
Varinant 1: It looks like you would like to use ranking function.
if objcet_id('tempdb..#TmpOrderedTable') is not null drop table #TmpOrderedTable
select *, row_number(order by columnlist, (select 0)) rn
into #TmpOrderedTable
from table1 t
select *
from #TmpOrderedTable t0
inner join #TmpOrderedTable tplus on t0.rn = tplus.rn + 1 -- next one
inner join #TmpOrderedTable tminus on t0.rn = tminus.rn - 1 -- previous one
Varinant 2:
To get scalar values you can use ranking function lag and lead. Or subquery.
Varinant 3:
You can use selfjoin, but you have to specify unique nonarbitary key if you don't want duplicates.
Varinant 4:
You can use apply.
Your question isn't too clear, so i hope it was your goal.
How about this?
WITH ts as (
SELECT t.theDate as theDate1, s.theDate as theDate2,
t.bitField as bitField1, s.bitField as bitField2,
t.NAME -- there is only one name
FROM table1 t INNER JOIN
table1 s
ON t.NAME = s.NAME
)
SELECT ts.*
FROM ts
WHERE EXISTS (SELECT 1
FROM ts ts2
WHERE ts2.name = ts.name AND
ts2.theDate1 = ts.theDate2 AND
ts2.theDate2 = ts.theDate1 AND
ts2.bitField1 = ts.bitField2 AND
ts2.bitField2 = ts.bitField1
);
I have a table task
select
sts_id,
count(*) mycount
from
task
where
sts_id in (1, 8, 39)
group by sts_id;
output :
sts_id count
1 1
8 1
39 1
I have one more temp table with one column sts_id
which looks like this
sts_id
1
8
39
40
41.
I am trying for a left join for both the tables
select
in_list.sts_id,
count(*) mycount
from
task
left outer join
in_list
on task.sts_id = in_list.sts_id
group by sts_id;
to get ab o/p like
1 1
8 1
39 1
40 0
41 0..
I am getting an error of column ambiguously defined.
You are using left join the wrong way (on the left it must be the table with all the rows you want to show).
Count (task.sts_id) to get 0 on rows without ocurrences on that table
select
in_list.sts_id,
count(task.sts_id) mycount
from
in_list
left outer join
task
on in_list.sts_id = task.sts_id
AND task.sts_id in (1, 8, 39) -- Thanks Matt.
group by in_list.sts_id;
You are missing the table alias in the GROUP BY clause.
However, your needed result says that you need to change your join logic: the starting table should be in_list, while task should be in left outer join:
select ...
from in_list
left outer join task
select
in_list.sts_id,
coalesce(count(task.sts_ID),0) mycount --changed this line
from
task
right outer join --changed this line
in_list
on task.sts_id = in_list.sts_id
group by in_list.sts_id; -- changed this line
Reasons:
as in_list contains more data than task, we needed to either change the table order or make it a right join
Count would count all records and not return resutls you want the count from task
need to coalesce the results otherwise null count will return null not 0.
I got my answer with this query
select t2.sts_id, count(t.sts_id)
from task t, in_list t2
where t2.sts_id = t.sts_id(+)
group by t2.sts_id
Thanks,
I am trying to turn a "simplified" sql query into a working SQLite one to use against XnViews databases, meaning the database layout is at best suboptimal for what I'm trying to do AND I can't change anything about that.
Example would be "(cat_10 and cat_12) and (cat_5 or cat_7)".
This should be used against the table "t3", which has the fields "if" (fileID) and "ic" (categoryID).
The entries look like this:
if, ic
7, 10
7, 12
7, 4
9, 10
9, 12
9, 5
10, 10
10, 12
10, 7
The simplified query above should only select the files 9 and 10 as 7 does have the wanted categories 10 and 12 but has neither 5 nor 7.
The actual problem now is building that hell of a query statement because it took me already some hours to simply get an AND between two categories working.
SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2
This gives me all fileIDs that contain category 10 and 12, but I have no idea how I should combine that with the remaining " and (cat_5 or cat_7)".
When I planned these simplified sql statements (made by a click-it-together-builder made in html and js) I was planning to simply replace "cat_5" with "t3.ic = 5" and leave the rest as it is.
Of course I didn't forsee that it wouldn't work as where checks the entry as a whole and there can't be ic = 5 AND ic = 7. That pretty much broke everything.
So I'm wondering if anyone would have an idea how I could translate these simple queries in actual working ones, keeping in mind that it might not be limited to ( x and y ) pairs.
Edit: I worked out how to do the example I've given, I think atleast:
SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2
INTERSECT
SELECT if FROM t3 WHERE ic IN (5, 7) GROUP BY if
But the main problem now is resolving the ( ) in the right order.
Edit 2: I think I'm giving grouping the categories into one field with group_concat() a try, then I should be able to simply to cats LIKE " " AND which would be small blocks I could easy throw together, then just the brackets and it should work. Highlighting the 'should'.
Your original query doesn't do what is intended. WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2 would yield the right result even when you have ics in 10 and 10 again but not 12 at all. This is against your textual description of what you want. This is where an inner query to fetch results for 12 and 10 is needed. You can test your query to fail in the fiddle link I have posted below.
Bit tricky, but this is how I would interpret it straightforward.
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
GROUP BY ifc
HAVING COUNT(*) > 0
INTERSECT
SELECT ifc
FROM t3
WHERE ic = 12
GROUP BY ifc
HAVING COUNT(*) > 0
)
AND ic IN (5, 7)
Try fiddle
I did not bring in any optimization, you may try yours. The fiddle link is of Postgres but this should work ( did not get SQLite to work in my browser :( )
Edit: CL. points out an interesting thing about not having to include HAVING clauses in the inner query which is true. I was interpreting OP's requirement in SQL terms with an intent to make things clear without thinking of any optimizations.
Here is a better looking query:
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
INTERSECT
SELECT ifc
FROM t3
WHERE ic = 12
)
AND ic IN (5, 7)
Ok I got it working as I originally planned surprisingly.
SELECT Folders.Pathname || Images.Filename AS File FROM Images
JOIN Folders ON Images.FolderID = Folders.FolderID
LEFT JOIN (
SELECT f, Cats, t4.if AS Tagged FROM t2
JOIN (
SELECT if, ' ' || group_concat(ic,' ') || ' ' AS Cats FROM t3 GROUP BY if
) st3 ON t2.i = st3.if
LEFT JOIN t4 ON t2.i = t4.if
) st2 ON File = st2.f
$selectWhereImage $sqlqry
ORDER BY ModifiedDate $order LIMIT $offset, $limit
I know this is one hell of a query but it combines all things I'd be looking for (category ids, tagged or not, rating, color) sortable by date with the full filepath as result.
It's probably a horrible way to do it but if anyone finds a better working way where I can simply replace placeholders like "cat_5" while keeping the rest like it is, needed for brackets and operators, then I'm all ears :D
Oh and $selectWhereImage contains just a longer WHERE that limits File to be ending with an imageformat, $sqlqry is the refittet thing from above, cat_5 would just turn into cats LIKE '% 5 %', due to the additional spaces left and right of cats I can match any number without finding "1" in "10" since " 1 " isn't in " 10 " :D
A hackish approach which would be simpler and I believe faster is
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
)
AND ifc IN (
SELECT ifc
FROM t3
WHERE ic = 12
)
AND ic IN (5, 7)
If you have to use an intersect as you have done you should change your upper query which is wrong. Since you have to ensure every if has a 10 and 12 as ic then you can't get away without two separate queries for that. Something like:
SELECT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
)
AND ifc IN (
SELECT ifc
FROM t3
WHERE ic = 12
)
INTERSECT
SELECT ifc FROM t3 WHERE ic IN (5, 7)
The INTERSECT will handle the group by here so you dont have to explicitly add but this will not be as efficient as my other queries. If you have to get away with subqueries, you can use JOIN:
SELECT DISTINCT t.ifc
FROM t3 AS t
JOIN t3 AS v ON v.ifc = t.ifc
JOIN t3 AS p ON p.ifc = t.ifc
WHERE v.ic = 10 AND p.ic = 12 AND t.ic IN (5, 7)
The second one has the advantage that it works on databases that doesn't know INTERSECT like MySQL.