How to query the name of each section and the number of threads at it using sql query? - sql

I have 2 tables at mysql database the first one contains parts like this:
parts
primary part_name part_id
0 web 1
0 graphic 2
1 php 3
1 asp 4
2 photoshop 5
2 illustrator 6
1 html 7
some of parts are primary like web, graphic. and others are subsections
for example web section contains (php,asp,html) parts
so at primary field there is the id of father part
graphic part contains (photoshop, illustrator) parts.
the other table is for posts;
posts
post_content post_title part_id post_id
anything any title 3 1
anything any title 6 2
anything any title 3 3
anything any title 3 4
anything any title 7 5
anything any title 6 6
anything any title 4 7
anything any title 4 8
anything any title 3 9
I want to get a table contains the main parts (primary = 0)
and sum of posts at it
the result should be like this;
query result
count_posts part_name part_id
7 web 1
2 graphic 2
I tried this:
SELECT p.*,count(s.post_id)
FROM part p,post s
where s.part_id = 1
and p.belong = 1
but it get results only for one part

Can't yet comment on other posts than my own so I'm submiting a new answer.
#StuartLC answer is missing the join between primary parts and subsections.
SELECT COUNT(po.post_id) AS count_posts, pa.part_name, pa.part_id
FROM parts pa
INNER JOIN parts pa2 on pa2.[primary] = pa.part_id
INNER JOIN posts po on po.part_id = pa2.part_id
WHERE pa.[primary] = 0
GROUP BY pa.part_name, pa.part_id
http://sqlfiddle.com/#!6/1dd90/3/0

Related

How to assign data without repetition in SQL

I need to create automatic weekly assignments of items to sites for my employees.
The items table items_bank looks like that(of course there will be a lot of items with few more languages) :
**item_id** **item_name** **language**
1 Jorge Garcia English
2 Chrissy Metz English
3 Nina Hagen German
4 Harald Glööckle German
5 Melissa Anderson French
6 Pauley Perrette French
My second table is the sites table :
**site_id** **site_name**
1 DR
2 LI
3 IG
I need to assign every week items to the sites with the following constraints :
For each site assign at least X items of English, Y items of German, and so on...
we want to create diversity - so we would like to avoid repeating the assignments of the 2 weeks before
I think we need to create another table in which we can save there the history of the last 2 weeks' assignments.
right now I managed to create an SQL query that assigns items but I don't know how to take the constraints under consideration this is what I create so far :
WITH numbered_tasks AS (
SELECT t.*, row_number() OVER (ORDER BY rand()) item_number, count(*) OVER () total_items
FROM item_bank t
),
numbered_employees AS (
SELECT e.*,row_number() OVER (ORDER BY rand()) site_number,
count(*) OVER () total_sites
FROM sites_bank e
)
SELECT nt.item_name,
ne.acronym
FROM numbered_tasks nt
INNER JOIN numbered_employees ne
ON ne.site_number-1 = mod(nt.item_number-1, ne.total_sites)
Expected results are for the example which says :
site_id=1 have to get 1 item with the English language
site_id=2 have to get 1 item with the German language
site_id=1 have to get 1 item with the French language
**item_id** **language** **Week_number** **site**
1 English 1 1
4 German 1 2
5 French 1 3
Any help will be appreciated!

Using TOP 1 (or CROSS APPLY) within multiple joins

I've reviewed multiple Q&A involving TOP 1 and CROSS APPLY (including the very informative 2043259), but I still can't figure out how to solve my issue. If I had a single join I'd be fine, but fitting TOP 1 into the middle of a chain of joins has stumped me.
I have four tables and one of the tables contains multiple matches when joining due to a previous bug (since fixed) that created new records in the table instead of updating existing records. In all cases, where there are multiple records, it is the top-most record that I want to use in one of my joins. I don't have access to the table to clean up the extraneous data, so I just have to deal with it.
The purpose of my query is to return a list of all "Buildings" managed by a particular person (user choses a person's name and they get back a list of all buildings managed by that person). My tables are:
Building (a list of all buildings):
BuildingId BuildingName
1 Oak Tree Lane
2 Lighthoue Court
3 Fairview Lane
4 Starview Heights
WebBuildingMapping (mapping of BuidingId from Building table, that is part of an old system, and corresponding WebBuildingId in another piece of software):
BuildingId WebBuildingId
1 201
2 202
3 203
4 204
WebBuildingContacts (list of ContactID for the building manager of each building). This is the table with duplicate values - where I want to choose the TOP 1. In sample data below, there are two references to WebBuidingId = 203 (row 3 & row 5) - I only want to use row 3 data in my join.
Id WebBuildingId ContactId
1 201 1301
2 202 1301
3 203 1303
4 204 1302
5 203 1302
Contacts (list of ContactIds and corresponding property manager Names)
ContactId FullName
1301 John
1302 Mike
1303 Judy
As noted, in the example above, the table WebBuildingContact has two entries for the building with a WebBuidingId = 203 (row 3 and row 5). In my query, I want to select the top one (row 3).
My original query for a list of buildings managed by 'Mike' is:
SELECT BuildingName
FROM Building bu
JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
JOIN WebBuildingContact wbc ON wbc.WebBuildingId = wbm.WebBuildingId
JOIN Contacts co ON co.ContactId = wbc.ContactId
WHERE co.FullName = 'Mike'
This returns 'Fairview Lane' and 'Starview Heights'; however, Judy manages 'Fairview Lane' (she's the top entry in the WebBuildingContacts table). To modify the query and eliminate row 5 in WebBuildingContacts from the join, I did the following:
SELECT BuildingName
FROM Building bu
JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
JOIN WebBuildingContact wbc ON wbc.WebBuildingId =
(
SELECT TOP 1 WebBuildingId
FROM WebBuildingContact
WHERE WebBuildingContact.WebBuildingId = wbm.WebBuildingId
)
JOIN Contacts co ON co.ContactId = wbc.ContactId
WHERE co.FullName = 'Mike'
When I try this; however, I get the same result set (ie it returns 'Mike' as manager for 2 buildings). I've also made various attempts to use CROSS APPLY but I just end up with 'The multi-part identifier could not be bound', which is a whole other rabbit hole to go down.
You could try this:
SELECT bu2.BuildingName
FROM building bu2
WHERE bu2.BuildingId IN
(SELECT MAX(bu.BuildingId)
FROM Building bu
JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
JOIN WebBuildingContact wbc ON wbc.WebBuildingId = wbm.WebBuildingId
JOIN Contacts co ON co.ContactId = wbc.ContactId
WHERE co.FullName = 'Mike'
);

Knex.js Getting values from comma-separated

I have two SQlite3 tables task and tags
task is my master table and tags is storing tag names
I store comma-separated values in task
Now I want to get Tag names with use of a knex.js
table task
id task tags
---------------------
1 abc 1,2,3
2 xyz 3,1
3 apple 2
table tags
id tag
------------
1 cold
2 hot
3 normal
Now i want output as below
OUTPUT:
id task tags
---------------------
1 abc cold,hot,normal
2 xyz normal,cold
3 apple hot
I know i will have to use joins but not sure how to actually use it in knex.js. Please do help me.
Part of the problem is that your database is not properly normalised. Instead of having two tables task and tabs, with table tasks containing multiple tag IDs in the column 'tags' you should have three tables; 'tasks', 'tags' and the 'joining' table 'task_tags'. They would store the following data...
Tasks
id task
----------
1 abc
2 xyz
3 apple
Tags
id tag
------------
1 cold
2 hot
3 normal
task_tags
task_id tag_id
1 1
1 2
1 3
2 1
2 3
3 2
Now you can have as many tags as you like (whether or not any tasks use them) and as many tasks as you like (whether or not they use any tags) and you associate a task with it's tags via the task_tags table.
Then to get the result you want you would use the select
SELECT
tasks.id,
tasks.task,
GROUP_CONCAT(tags.tag) -- this gives you the csv line eg cold,hot,normal
from tasks
left join task_tags
ON tasks.id = task_tags.task_id
left join tags
on tags.id = task_tags.tag_id
GROUP BY task.id, tags.id
see https://www.sqlite.org/lang_aggfunc.html for explanation of GROUP_CONCAT
Your task table should be redesigned to hold one tag per row, not multiple tags in a single row:
id task tag
---------- ---------- ----------
1 abc 1
1 abc 2
1 abc 3
2 xyz 3
2 xyz 1
3 apple 2
Then it's easy:
SELECT task.id, task.task, group_concat(tags.tag, ',') AS tags
FROM task
JOIN tags ON task.tag = tags.id
GROUP BY task.id, task.task
ORDER BY task.id;
which gives
id task tags
---------- ---------- ---------------
1 abc cold,hot,normal
2 xyz normal,cold
3 apple hot
A design that follows the rules of relational databases makes life much easier (And the above can be normalized further; see the other answer); while some databases do support array types, sqlite is not one of them. If you insist on keeping your current design, though, there's an ugly hack involving the JSON1 extension and turning your CSV list of numbers into a JSON array:
SELECT task.id, task.task, group_concat(tags.tag, ',') AS tags
FROM task
JOIN json_each('[' || task.tags || ']') AS j
JOIN tags ON tags.id = j.value
GROUP BY task.id, task.task
ORDER BY task.id;

Recursive tree search using postgresql join table

I have a table stories and a table blockings which has the columns story_id (referencing a story), and a blocked_story_id (also referencing a story, which is blocked by the story_id)
I'm trying to construct a query to return all the stories in order of precedence based on their blockers - so blockers first, traversing down the tree.
One story can be blocked by many stories, and can itself be a blocker for many stories.
I've been reading and re-reading the PostgreSQL docs on WITH RECURSIVE but I'm a little lost on where I should be going with this, and how to construct the relevant query.
I have got as far as:
select s.id, b.story_id as blocker_id
from stories s
left outer join blockings b on s.id = b.blocked_story_id
where s.deleted_at is null
as for getting a list of stories and their blockers, but some pointers as to what I need to join/union to get the desired result would be helpful.
Context
I want to know which stories I can work on first. So I want an output that contains all stories in an order that allows me to work top down and never hit a blocked story.
The content of the blockings table gives me a simple join table between stories that block one another. The story_id being the blocker, the blocked_story_id being the one being blocked.
Sample Data
Stories
id | title
------------------
1 | Story title 1
2 | Story title 2
3 | Story title 3
4 | Story title 4
5 | Story title 5
Blockings
story_id | blocked_story_id
---------------------------
4 | 2
4 | 3
3 | 1
3 | 5
I would expect to see the following result:
id | title
------------------
4 | Story title 4
2 | Story title 2
3 | Story title 3
1 | Story title 1
5 | Story title 5
Disclaimer: Because it is not clear to me why you need a recursion for finding the blocked stories (Which can be achieved easily by SELECT blocked_story_id FROM blocking) I would ask you for further information. A real recursion case could be: "All blocking that are reachable from story 4" or something like that.
Here's what I've done so far as I understood your problem:
Your blocking table says: story 4 blocks stories 2 and 3. Story 3 blocks stories 1 and 5. So there are blocked stories 1, 2, 3, 5. Because of the recursion, story 4 can block 1 and 5 via 3. So there a two ways of blocking them (directly with starting point 3 and and from starting point 4 via 3). I gave out all possible paths with this query:
WITH RECURSIVE blocks AS (
SELECT blocked_story_id, ARRAY[story_id]::int[] as path FROM blockings
UNION
SELECT bk.blocked_story_id, b.path || bk.story_id
FROM blockings bk INNER JOIN blocks b ON b.blocked_story_id = bk.story_id
)
SELECT b.blocked_story_id, s.title, b.path
FROM blocks b INNER JOIN stories s ON s.id = b.blocked_story_id;
Result:
blocked_story_id title path
2 Title 2 {4}
3 Title 3 {4}
1 Title 1 {3}
5 Title 5 {3}
1 Title 1 {4,3}
5 Title 5 {4,3}
demo: db<>fiddle
#S-Man I figured it out thanks to your help pointing me in the right direction.
WITH recursive blockings_tree(id, title, path) AS (
SELECT stories.id, title, ARRAY[blockings.blocked_story_id, blockings.story_id]
FROM stories
LEFT OUTER JOIN blockings ON blockings.story_id = stories.id
UNION ALL
SELECT stories.id, stories.title, path || stories.id
FROM blockings_tree
JOIN blockings ON blockings.story_id = blockings_tree.id
JOIN stories ON blockings.blocked_story_id = stories.id
WHERE NOT blockings.blocked_story_id = any(path)
)
SELECT stories.*
FROM stories
JOIN (SELECT id, MAX(path) AS path FROM blockings_tree GROUP BY id) bt ON bt.id = stories.id
ORDER BY path

Indexing one to many relational structure in solr

I have a schema like the following that I want to index in SOLR. But I am not sure how to manage the one to many relationship between the first table: users and second table: address
ID NAME DESCRIPTION
-------------------------------------------------
1 NAME1 DEMO DESCRIPTION ONE
2 NAME2 DEMO DESCRIPTION TWO
3 NAME3 DEMO DESCRIPTION THREE
-------------------------------------------------
ADDR_ID USER_ID CITY STATE COUNTRY
-------------------------------------------------
1 1 cityv statev countryv
2 1 cityw statew countryw
3 2 cityx statex countryx
4 2 cityy statey countryy
5 3 cityz statez countryz
How to index users with multiple addresses?
Also how to search them by either users.name, address.city / address.state name?
Try Block Join with parent/child structure