sql return categories ordered by blog post date - sql

I've a Wordpress website with articles. A post can contain or more categories (table wp_terms). Now I want a query that returns a list of all term names, ORDERED BY the blogs article date. I have experimented with a SELECT in a SELECT query, but that doesn't work... How can I do it and return the categories ordered by the article date?
table wp_posts (as example):
|ID------|post_title------------------|post_date-|
|1 |Test title |2014-05-05|
|2 |Test title 2 |2014-04-01|
|3 |Last test title |2014-02-02|
|4 |Another blog item |2014-01-06|
table wp_terms:
|term_id|name---------|
|1 |computers |
|2 |home |
|3 |work |
table wp_term_relationships
|object_id|term_taxonomy_id|term_order|
|1 |2 | 0 |
|1 |1 | 0 |
|2 |3 | 0 |
table wp_term_taxonomy
|term_taxonomy_id | term_id |
|1 |1 |
|2 |2 |
|3 |3 |
|4 |4 |
This is my current query, but this doesn't work right...
SELECT t.*, p.* FROM wp_terms AS t
JOIN wp_term_taxonomy AS tt ON tt.term_id = t.term_id
JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tr.term_taxonomy_id
LEFT JOIN ( SELECT `ID`, `post_title`, max(`post_date`) as `date` FROM wp_posts
GROUP BY `ID` ) as p on p.`ID`= tr.`object_id` GROUP BY t.`term_id` ORDER BY p.`date` desc

Still not sure what you are trying to achieve. But this is your query which runs without errors
SELECT t.*, p.*
FROM wp_terms AS t JOIN wp_terms_taxonomy AS tt
ON tt.term_id = t.term_id
JOIN wp_terms_relationship AS tr
ON tr.term_taxonomy_id
= tr.term_taxonomy_id LEFT JOIN
( SELECT ID, post_title, max(post_date) as date
FROM wp_posts
GROUP BY ID , post_title) as p on p.ID= tr.object_id
GROUP BY t.term_id,t.name,p.id,p.post_title,p.date
ORDER BY p.date desc
fiddle

Related

How to disregard a row in a returned MS Access query when all fields bar one are distinct

I'm trying to create a query on Access 2010 which only produces a single row per patient. There are a really small number of patients (each patient represented by
a unique nhs_number in the table n) who are listed as having 2 practices in the table pp and so two rows are generated for them. Is there a way I can arbitrarily select one of the practices and ignore the other?
This is the query:
SELECT DISTINCT
n.nhs_number,
IIF(ch.care_home_date>#2/1/1900#, "TRUE", "FALSE") AS care_home,
pp.practice
FROM (nhs_no_tbl AS n
LEFT JOIN patient_practice_tbl AS pp ON n.nhs_number = pp.nhs_number)
LEFT JOIN patient_care_home_tbl AS ch ON n.nhs_number = ch.nhs_number;
The tables the query is using contains data along these lines:
nhs_no_tbl:
|nhs_number|
| -------- |
|1 |
|2 |
|3 |
|4 |
patient_practice_tbl:
|nhs_number|practice|
| -------- | ------ |
|1 |GP_A |
|2 |GP_A |
|3 |GP_B |
|4 |GP_A |
|4 |GP_B |
patient_care_home_tbl:
|nhs_number|care_home_date|
| -------- | ------------ |
|1 |1/5/2000 |
|1 |1/10/2010 |
|4 |26/10/2017 |
At the end, I'd like the query to return the following:
|nhs_number|Care_home|practice|
| -------- | ------- | ------ |
|1 |TRUE |GP_A |
|2 |FALSE | |
|3 |FALSE | |
|4 |TRUE |GP_A [or GP_B] |
I've update the query with CTE,
;WITH cte1 AS ---select all results
(
SELECT DISTINCT nnt.nhs_number,
CASE WHEN pcht.care_home_date IS NULL
THEN 'FALSE'
ELSE 'TRUE'
END AS CareHome,
ppt.practice,
rank()OVER(PARTITION BY nnt.nhs_number ORDER BY ppt.practice) AS R
FROM #nhs_no_tbl nnt
LEFT JOIN #patient_practice_tbl ppt ON nnt.nhs_number = ppt.nhs_number
LEFT JOIN #patient_care_home_tbl pcht ON nnt.nhs_number = pcht.nhs_number
),
CTE2 AS ---choose who may have multiple pracices
(
SELECT nhs_number
FROM CTE1
WHERE R = 2
),
CTE3 AS --- combine GP_A and GP_B
(
SELECT t.nhs_number,STRING_AGG(val,',') AS Practices
FROM
(
SELECT DISTINCT val = cte1.practice, CTE1.nhs_number
FROM #nhs_no_tbl nnt
INNER JOIN CTE2 ON nnt.nhs_number = CTE2.nhs_number
INNER JOIN cte1 ON nnt.nhs_number = CTE1.nhs_number
) t
--RIGHT JOIN #nhs_no_tbl nnt ON t.nhs_number = nnt.nhs_number
GROUP BY t.nhs_number
)
SELECT cte1.nhs_number,cte1.carehome,cte1.practice, cte3.Practices
FROM CTE1
LEFT JOIN cte3 ON cte1.nhs_number = CTE3.nhs_number
The result would be
then next you could store the result into a temp table and update temp table where practices is not null.

Max value from joined table

I have two tables:
Operations (op_id,super,name,last)
Orders (or_id,number)
Operations:
+--------------------------------+
|op_id| super| name | last|
+--------------------------------+
|1 1 OperationXX 1 |
|2 1 OperationXY 2 |
|3 1 OperationXC 4 |
|4 1 OperationXZ 3 |
|5 2 OperationXX 1 |
|6 3 OperationXY 2 |
|7 4 OperationXC 1 |
|8 4 OperationXZ 2 |
+--------------------------------+
Orders:
+--------------+
|or_id | number|
+--------------+
|1 2UY |
|2 23X |
|3 xx2 |
|4 121 |
+--------------+
I need query to get table:
+-------------------------------------+
|or_id |number |max(last)| name |
|1 2UY 4 OperationXC|
|2 23X 1 OperationXX|
|3 xx2 2 OperationXY|
|4 121 2 OperationXZ|
+-------------------------------------+
use corelared subquery and join
select o.*,a.last,a.name from
(
select super,name,last from Operations from operations t
where last = (select max(last) from operations t2 where t2.super=t.super)
) a join orders o on t1.super =o.or_id
you can use row_number as well
with cte as
(
select * from
(
select * , row_number() over(partition by super order by last desc) rn
from operations
) tt where rn=1
) select o.*,cte.last,cte.name from Orders o join cte on o.or_id=cte.super
SELECT Orders.or_id, Orders.number, Operations.name, Operations.last AS max
FROM Orders
INNER JOIN Operations on Operations.super = Orders.or_id
GROUP BY Orders.or_id, Orders.number, Operations.name;
I don't have a way of testing this right now, but I think this is it.
Also, you didn't specify the foreign key, so the join might be wrong.

Join 2 Lookup Tables to a Detail table

I have 3 tables:
Products
Groups
Sales
The products table contains the following information:
|**Product ID**|**Product Description**|
|--------------|-----------------------|
|1 |Wine |
|2 |Ruler |
|3 |Gas |
|4 |Water |
The Groups table contains the following information:
|**Group ID**|**Group Description**|
|------------|---------------------|
|1 |Cheetahs |
|2 |Elephants |
|3 |Cougars |
The Sales table contains the following information:
|**GroupID**|**Product ID**|**Amount Sold**|**Day Sold**|
|-----------|--------------|---------------|------------|
|1 |2 | 3|07-31-2016 |
|1 |1 | 1|07-31-2016 |
|2 |3 | 5|07-31-2016 |
|1 |4 | 2|08-01-2016 |
Now I have to produce a query that could bring me a result set as follows (with the condition that I want only results from 07-31-2016):
|**Group ID**|**Product ID**|**Amount Sold**|
|------------|--------------|---------------|
|1 |1 |1 |
|1 |2 |3 |
|1 |3 |0 |
|1 |4 |0 |
|2 |1 |0 |
|2 |2 |0 |
|2 |3 |5 |
|2 |4 |0 |
|3 |1 |0 |
|3 |2 |0 |
|3 |3 |0 |
|3 |4 |0 |
I thought this was going to be just a matter of using left joins, but it appears it wouldn't bring me back the result I was looking for (I don't want to omit products nor groups which weren't sold).
So in summary, I need to display all groups and all products no matter if they had an appearance in the Sales table.
I would appreciate any feedback on this matter, directions on where to look at or any logic that I may be missing!
EDIT
I've marked Matt's (big thanks) post as the answer, turns out I've never used a cross join.
I only added the where clause inside the left join of the Sales table in order to get just the sales made on 07-31-2016
SELECT
g.GroupId
,p.ProductId
,SUM(COALESCE(s.AmountSold,0)) as AmountSold
FROM
Products p
CROSS JOIN Groups g
LEFT JOIN Sales s
ON p.ProductId = s.ProductId
AND g.GroupId = s.GroupId
AND daySold = '07-31-2016'
GROUP BY
g.GroupId
,p.ProductId
ORDER BY
g.GroupId
,p.ProductId
SELECT
g.GroupId
,p.ProductId
,SUM(COALESCE(s.AmountSold,0)) as AmountSold
FROM
Products p
CROSS JOIN Groups g
LEFT JOIN Sales s
ON p.ProductId = s.ProductId
AND g.GroupId = s.GroupId
AND s.daySold = '07-31-2016'
GROUP BY
g.GroupId
,p.ProductId
ORDER BY
g.GroupId
,p.ProductId
Note your expected results you provided are wrong for group 1 product 4 there were 2 of those in the sale.
You could join all the Products with all the Groups (so you get a list of all the combinations of the two) and then add the additional information (filtering out the results based on your condition with a WHERE statement.
SELECT A.[Group ID]
, B.[Product ID]
, ISNULL([Amount Sold], 0) AS 'Amount Sold'
FROM Groups A
INNER JOIN Products B
ON 1 = 1
LEFT JOIN Sales C
ON C.[Group ID] = A.[Group ID]
AND C.[Product ID] = B.[Product ID]
WHERE [Day Sold] = '07-31-2016'

Return rows only if matches all list values

Let's say I have a table customers:
-----------------
|id|name|country|
|1 |Joe |Mexico |
|2 |Mary|USA |
|3 |Jim |France |
-----------------
And a table languages:
-------------
|id|language|
|1 |English |
|2 |Spanish |
|3 |French |
-------------
And a table cust_lang:
------------------
|id|custId|langId|
|1 |1 |1 |
|2 |1 |2 |
|3 |2 |1 |
|4 |3 |3 |
------------------
Given a list: ["English", "Spanish", "Portugese"]
Using a WHERE IN for the list, it will still return customers with ids 1,2 because they match "English" and "Spanish".
However, the results should be 0 rows returned since no customer matches ALL three terms.
I only want the customer ids to return if it matches the cust_lang table.
For instance, Given a list: ["English", "Spanish"]
I would want the results to be customer Id 1, since he alone speaks both languages.
EDIT: #GordonLinoff - That works!!
Now to make it more complex, what's wrong with this additional related query:
Let's assume I also have a table degrees:
-----------
|id|degree|
|1 |PHD |
|2 |BA |
|3 |MD |
-----------
A corresponding join table cust_deg:
------------------
|id|custId|degId |
|1 |1 |1 |
|2 |1 |2 |
|3 |2 |1 |
|4 |3 |3 |
------------------
The following query does not work. However, it is two of the same queries combined. The results should be only rows that match both lists, instead of the one list.
SELECT * FROM customers C
WHERE C.id IN (
SELECT CL.langId FROM cust_lang CL
JOIN languages L on CL.langId = L.id
WHERE L.language IN ("English", "Spanish")
GROUP BY CL.langID
HAVING COUNT(*) = 2)
AND C.id IN (
SELECT CD.custId FROM cust_deg CD
JOIN degrees D ON CD.degID = D.id
WHERE D.degree IN ("PHD", "BA")
GROUP BY CD.custId HAVING COUNT(*) = 2));`
EDIT2: I think i fixed it. I accidentally had an extra select statement in there.
You can do this with group by and having:
select cl.custid
from cust_lang cl join
languages l
on cl.langid = l.id
where l.language in ('English', 'Spanish', 'Portuguese')
group by cl.custid
having count(*) = 3;
If, for example, you only wanted to check for two languages, then you need only change you WHERE ... IN and HAVING conditions, e.g.:
where l.language in ('English', 'Spanish')
and
having count(*) = 2
This is pretty much Gordon's answer but it has the benefit of being a little more flexible on the language list and it doesn't require any change to the having clause.
with my_languages as (
select langId from languages
where language in ('English', 'Spanish')
)
select cl.custId
from cust_lang as cl inner join my_languages as l on l.langId = cl.langId
group by cl.custId
having count(*) = (select count(*) from lang)

Oracle SQL: Joining another table with one missing tuple

I have the following two tables, one stores order information, one stores key|value information.
There is no CD = D for key COLOR_CD. I would like to join both tables to get all orders irregardless of the key|value pair not found in the MASS_DECODE table.
Can i get some help please :D
ORDER_INFORMATION
ORDER_NUMBER |COLOR_CD |
----------------|-----------|
1 |A |
2 |B |
3 |C |
4 |D |
MASS_DECODE
KEY |CD |VALUE |
------------|---------------|-----------|
COLOR_CD |A |Green |
COLOR_CD |B |Blue |
COLOR_CD |C |Red |
SIZE_CD |A |Large |
SIZE_CD |B |Medium |
SIZE_CD |C |Small |
SQL:
select order_number, cd, value
from order_information
left outer join mass_decode
on (color_cd = cd)
and key = 'COLOR_CD';
Outcome:
ORDER_NUMBER |CD |VALUE |
----------------|-----------|-----------|
1 |A |Green |
2 |B |Blue |
3 |C |Red |
Expected:
ORDER_NUMBER |CD |VALUE |
----------------|-----------|-----------|
1 |A |Green |
2 |B |Blue |
3 |C |Red |
4 |D |NULL |
EDIT: I am sorry i have presented incorrect information for my tables. Since been corrected.
select *
from order_information oi
left join mass_decode md
on (
oi.color_cd = md.cd
and oi.key = md.key
)
where oi.key = 'KEY_A';
SQLFiddle
upd:
According to your updates:
select *
from order_information oi
left join mass_decode md
on oi.color_cd = md.cd
where md.key = 'COLOR_CD' or md.key is null;
SQLFiddle
Your column names are ambiguous. You have two columns named the same in two tables, so which column does the key in your where clause refer to? I think in later versions of Oracle, this will actually give you an error. Try this:
select oi.order_number, oi.color_cd, md.value
from order_infomation oi
left outer join mass_decode md
on (oi.color_cd = md.cd)
where oi.key = 'KEY_A';
Edit:
Based on your response to #billy, it sounds like that wasn't working for you. You could also try putting the key predicate into the join clause:
select oi.order_number, oi.color_cd, md.value
from order_infomation oi
left outer join mass_decode md
on (oi.color_cd = md.cd) and oi.key = 'KEY_A';
This should do :
SELECT
order_number,
color_cd AS cd,
(
SELECT value FROM mass_decode m2 WHERE m2.key = o.key AND m2.cd = o.color_cd
) AS value
FROM order_information o
WHERE o.key = 'KEY_A'